반응형
Notice
Recent Posts
Recent Comments
Link
관리 메뉴

짧은코딩

TS 기본 기식(2) 본문

TS/TS(with ZeroCho)

TS 기본 기식(2)

5_hyun 2022. 8. 17. 15:14
반응형

타입 가드

function numOrStr(a:number|string) {
  a.toFixed(1);
}

numOrStr('123');
numOrStr(1);

이렇게 하면 ts는 모든 가능성을 열어두기 때문에 오류가 난다. 왜냐하면 toFixed는 number에서만 사용할 수 있기 때문이다.

toFixed는 매개변수 숫자만큼 소수점이 생긴다.

 

function numOrStr(a: number | string) {
  if (typeof a === "number") {
    a.toFixed(1);
  } else {
    a.charAt(3);
  }
}

numOrStr("123");
numOrStr(1);

따라서 이렇게 표시하면 number인 것이 확실해서 오류가 발생하지 않는다. 그리고 else 문으로 가면 string인 것을 안다.

Class

class A {
  aaa() {}
}

class B {
  bbb() {}
}

function aOrB(param: A | B) {
  if (param instanceof A) {
    param.aaa();
  }
}

aOrB(new A());
aOrB(new B());

클래스는 이름 자체를 타입 부분에 사용할 수 있다. 그리고 만드시 new를 붙여야한다.

if문으로 객체 구별

-type로 구분하는 법

type B = { type: "b"; bbb: string };
type C = { type: "c"; ccc: string };
type D = { type: "d"; ddd: string };

function typeCheck(a: B | C | D) {
  if (a.type === "b") {
    a.bbb;
  } else if (a.type === "c") {
    a.ccc;
  } else {
    a.ddd;
  }
}

if 문에서도 타입 추론을 해준다. 안에 속성으로 타입 추론을 해준다.

 

-속성으로 구분하는 법

type B = { type: "b"; bbb: string };
type C = { type: "c"; ccc: string };
type D = { type: "d"; ddd: string };

function typeCheck(a: B | C | D) {
  if ("bbb" in a) {
    a.bbb;
  } else if ("ccc" in a) {
    a.ccc;
  } else {
    a.ddd;
  }
}

이렇게 in 연산자를 활용하면 된다.

 

=> 나중에 코딩할 때 객체 안에다가 습관적으로 type을 달아주는 것이 좋다. 이로 구별을 할 수 있다. 이를 태그를 달아준다고 한다.

타입을 구분해주는 커스텀 함수

interface Cat {
  meow: number;
}
interface Dog {
  bow: number;
}

function catOrDog(a: Cat | Dog): a is Dog {
  if ((a as Cat).meow) {
    return false;
  }
  return true;
}

function pet(a: Cat | Dog) {
  if (catOrDog(a)) {
    console.log(a.bow);
  }
  if ("meow" in a) {
    console.log(a.meow);
  }
}

이렇게 CatOrDog 함수를 통해서 Dog인지 Cat인지 구분하는 함수를 만들고 구분할 수 있다.

is가 들어있는 함수는 커스텀 타입 가드 함수이다. 커스텀 타입 가드 함수는 if문 안에서 사용한다. 복잡해지면 사용하면 좋다.

Promise

Promise는 비동기이다. 

Promise가 실행중인 상태에서는 Pending 상태 -> 실행이 끝나면 실패하든 성공하든 Settled 상태이며 Settled 안에 (Resolved, Rejected), 즉 (성공, 실패)가 있는 것

 

예를 들어 promise.then().catch() 이렇게 하는데 then과 catch가 settled이다. 그리고 then이 Resolved, catch가 Rejected라고 부르는 것이다.

 

-PromisesettledResult

PromisesettledResult 안에 PromiseRejectedResult(실패)와 PromiseFulfilledResult(성공) 이렇게 나눠진다.

 

-예시

const isRejected = (
  input: PromiseSettledResult<unknown>
): input is PromiseRejectedResult => {
  return input.status === "rejected";
};

const isFulfilled = <T>(
  input: PromiseSettledResult<T>
): input is PromiseFulfilledResult<T> => {
  return input.status === "fulfilled";
};

const promise = await Promise.allSettled([
  Promise.resolve("a"),
  Promise.resolve("b"),
]);
// 실패한 애들만 모아두는 코드, 하지만 타입이 settled
const errors = promise.filter((promise) => promise.status === "rejected");
// 실패한 애들만 모아두는 코드, 타입이 Rejected
const errors2 = promise.filter(isRejected);

export {};

errors의 filter 안에 있는 코드와 isRejected의 코드는 사실 같은 것이다. 하지만 최종적인 타입에 차이가 있다.

인덱스 시그니처

type A = { a: string; b: string; c: string };
type B = { [key: string]: string };

const aaaa: B = { a: "hello", b: "world" };

타입 A와 B는 같은 것이다. B는 모든 값의 속성이 string이길 원하면 사용하면 된다.

type B = "Human" | "Mammal" | "Animal";
type A = { [Key in B]: number };

const aaaa: A = { Human: 123, Mammal: 5, Animal: 7 };

혹은 이렇게 in을 사용해서 타입을 제한을 걸 수 있다. 이렇게 하면 최대한 정확하게 타입을 정해줄 수 있다.

type B = "Human" | "Mammal" | "Animal";
type A = { [Key in B]: B };

const aaaa: A = { Human: "Animal", Mammal: "Human", Animal: "Mammal" };

이렇게도 사용이 가능하다. interface에서는 '|'와 '&'가 안되기 때문에 type을 사용한다. 

클래스

interface A {
  readonly a: string;
  b: string;
}
class B implements A {
  private a: string = "123";
  protected b: string = "world";
  c: string = "wow";

  method() {
    console.log(this.a);
    console.log(this.b);
    console.log(this.c);
  }
}

class C extends B {
  method() {
    console.log(this.a); //private이라 사용 불가
    console.log(this.b); // protected고 B가 부모라서 사용 가능
    console.log(this.c);
  }
}
new C().a;
new C().b;
new C().c;

클래스의 모양을 interface로 통제할 수 있다. public, protected, private을 사용할 수 있다. JAVA와 굉장히 유사하다.

  public protected private
클래스 내부 O O O
인스턴스 X X
상속 클래스 O O X

 

=> 자바 원칙에 의해 interface로 추상적 구현을 해줘야 하지만 JS다 보니까 interface를 생략해도 상관은 없다.

 

-abstract

abstract class B implements A {
  private a: string = "123";
  protected b: string = "world";
  c: string = "wow";

  abstract method(): void;
}

class C extends B {
  method() {
    console.log(this.a); //private이라 사용 불가
    console.log(this.b); // protected고 B가 부모라서 사용 가능
    console.log(this.c);
  }
}
new C().a;
new C().b;
new C().c;

abstract는 추상적으로만 만들어 두고 구현은 다른 곳에서 한다는 의미이다. 따라서 구현을 C 클래스에서 했다. abstract가 있는 것은 다른 클래스에서 반드시 구현해줘야 에러가 안난다.

=> 이런 abstract가 있기 때문에 interface를 잘 안쓴다. 

옵셔널 체이닝

function abc(a: number, b?: number, c?: number) {}
abc(1);
abc(1, 2);
abc(1, 2, 3);

? 위치가 중요하다. ?가 붙어 있는 것은 있어도 되고 없어도 된다.

function abc(...args: number[]) {}
abc(1);
abc(1, 2);
abc(1, 2, 3);

혹은 이렇게 하면 개수 제한이 없다.

 

오버로딩

interface Add {
  (x: number, y: number): number;
  (x: string, y: string): string;
}

const add: Add = (x: any, y: any) => x + y;

class A {
  add(x: number, y: number): number;
  add(x: string, y: string): string;
  add(x: any, y: any) {
    return x + y;
  }
}

const c = new A().add(1, 2);

이렇게 오버로딩이 가능하며 return하는 함수에서는 any를 사용해도 된다.

반응형

'TS > TS(with ZeroCho)' 카테고리의 다른 글

TS와 건망증  (0) 2022.08.20
리턴값, 매개변수의 대입 범위  (0) 2022.08.20
타입을 만드는 법  (0) 2022.08.20
제네릭  (0) 2022.08.18
TS 기본 지식  (0) 2022.08.11
Comments