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

짧은코딩

제네릭 본문

TS/TS(with ZeroCho)

제네릭

5_hyun 2022. 8. 18. 15:42
반응형

제네릭

-틀린 예시

function add(x: string | number, y: string | number): string | number {
  return x + y;
}

add(1, 2); // 3
add("1", "2"); // '12'

add(1, '2') // '12'
add('1', 2) // '12'

타입을 이렇게 정하면 아래 2줄 같은 경우 때문에 에러가 난다.

 

-제네릭 틀린 예시

function add<T>(x: T, y: T): T {
  return x + y;
}

add(1, 2); // 3
add("1", "2"); // '12'

add(true, false);
add(1, "2"); // '12'
add("1", 2); // '12'

T는 다 같은 타입이라는 의미이다. 하지만 add(true, false) 같은 경우도 성립이 돼서 이런 경우를 고쳐야 한다.

 

-extends

function add<T extends number | string>(x: T, y: T): T {
  return x + y;
}

add(1, 2); // 3
add("1", "2"); // '12'

add(true, false);
add(1, "2"); // '12'
add("1", 2); // '12'

이렇게 extends를 사용하면 그 뒤에 써 준 타입들만 허용한다는 의미이다. 따라서 위에 2개의 add만 되고 아래 3개는 에러가 난다.

function add<T extends number, K extends string>(x: T, y: K): T {
  return x + y;
}

add(1, 2); // 3
add("1", "2"); // '12'

add(true, false);
add("1", 2); // '12'
add(1, "2"); // '12'

제네릭을 2개 사용할 수도 있다. 다만 이 코드에서는 마지막 add만이 되고 위 4개는 에러가 난다.

 

-forEach로 예시

제네릭 덕분에 타입을 다 추론할 수 있다.

 

-ts가 타입 추론을 못 할 때

function add<T>(x: T, y: T): T {
  return x;
}

add<number>(1, 2);

ts가 타입 추론을 못하면 이렇게 타입을 정해 줄 수 있다.

 

-원하는 타입 추론을 하도록 만들어 주는 법

interface Array<T> {
  filter<S extends T>(
    predicate: (value: T, index: number, array: T[]) => value is S,
    thisArg?: any
  ): S[];
  filter(
    predicate: (value: T, index: number, array: T[]) => unknown,
    thisArg?: any
  ): T[];
}

const filtered = ["1", 2, "3", 4, "5"].filter(
  (value) => typeof value === "string"
);

이러면 filtered의 타입은 string | number이 된다. 하지만 string으로 만들어 주고 싶다.

여기서 interface의 두번째 filter부터 살펴 보면 리턴 값의 타입이 다 같은 T 라서 무조건 string | number가 될 수 밖에 없다. 하지만 첫번재 filter는 리턴 값의 타입이 다른 S라서 string으로 바꿀 수 있는 여지가 있다.

그렇기에 첫번째 filter을 활용하면 된다.

interface Array<T> {
  filter<S extends T>(
    predicate: (value: T, index: number, array: T[]) => value is S,
    thisArg?: any
  ): S[];
  filter(
    predicate: (value: T, index: number, array: T[]) => unknown,
    thisArg?: any
  ): T[];
}

const predicate = (value: string | number): value is string =>
  typeof value === "string";
const filtered = ["1", 2, "3", 4, "5"].filter(predicate);

 predicate를 interface의 첫번째 filter에서 따와서 만들어줬다. 이게 가능한 이유는 <S extends T>이며 이 의미는 string extends string | number이기 때문이다. 따라서 filtered는 string으로 추론하게 된다.

반응형

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

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