[Typescsript] 타입스크립트 올인원:Part-1(4)

14. forEach, map 제네릭 분석

 

1-1. foreEach

interface Array<T> {
  forEach(
    callbackfn: (value: T, index: number, array: T[]) => void,
    thisArg?: any
  ): void;
}

const a: Array<number> = [1, 2, 3];
a.forEach((value) => {
  console.log(value);
});

Array<number>는 number 타입의 요소를 가진 배열을 의미한다. 따라서 Array<T>는 Array<Number>가 되어서 하단 코드의 형태로 변환된다.

    callbackfn: (value: Number, index: number, array: Number[]) => void,

 

1-2. custom forEach 만들기

interface Arr<T> {
  forEach(callback: (item: T, index: number) => void): void;
}

const a: Arr<number> = [1, 2, 3];
a.forEach((list, index) => {
  console.log(list);
});

const b: Arr<string> = ["1", "2", "3"];
b.forEach((list) => {
  console.log(list);
});

⚠️: index를 사용하지 않아도 에러가 안나는 이유: TypeScript에서 배열의 콜백 함수의 매개변수는 선택적(optional)으로 처리되기 때문. 콜백 함수에서 정의된 매개변수보다 적은 수의 매개변수를 사용해도 가능하다.

 

 

2-1. map

interface Array<T> {
  map<U>(
    callbackfn: (value: T, index: number, array: T[]) => U,
    thisArg?: any
  ): U[];
}

반환값은 U 타입의 배열이고 T를 넣게 되면 새로운 반환값인 U를 반환하게 된다.

 

2-2. custom map 만들기

interface Arr<T> {
  map<S>(callback: (v: T, index: number) => S): S[];
}

const mapA: Arr<number> = [1, 2, 3];

const ca = mapA.map((value) => value + 1); // [2, 3, 4]
const cb = mapA.map((value) => value.toString()); // ['2', '3', '4']
const cc = mapA.map((value, index) => value % 2 === 0); // [false, true, false]

 

15. 공변성, 반공변성

공변성: A가 B의 서브타입이면, T<A>는 T<B>의 서브타입이다.

function formattedNumber(x: string): number {
  return +x;
}

formattedNumber("1");

type B = (x: string) => number | string;
const testFormattedNumber: B = formattedNumber;

number를 반환하는 formattedNumber를 number 또는 string을 반환하는 type B인 testFormattedNumber에 대입하면 오류가 나지 않는 이유는 매개변수 타입이 동일하고, 반환 타입은 number가 number | string의 서브타입이므로 공변성에 의해 허용되어 formattedNumber를 B 타입의 변수에 할당할 수 있다.

 

반공변성:  A가 B의 서브타입이면, T<B>는 T<A>의 서브타입이다.

function formattedNumber(x: string | number): number {
  return +x;
}

formattedNumber("1");

type B = (x: string) => number | string;
const testFormattedNumber: B = formattedNumber;

 

formattedNumber: string | number이고, B: string이다. string은 string | number의 서브타입이다. 매개변수 타입은 반공변적이므로, 슈퍼타입에서 서브타입으로의 할당이 허용된다.

 

매개변수: string | number ← string (반공변성 OK)
반환타입: number → number | string (공변성 OK)

 

  • 매개변수는 반공변성 규칙을 만족하고 (B의 매개변수 타입이 formattedNumber의 매개변수 타입의 서브타입)
  • 반환 타입은 공변성 규칙을 만족하므로 (formattedNumber의 반환 타입이 B의 반환 타입의 서브타입)

 

 

 

 

참조: 타입스크립트 공변성 & 반공변성 완벽 이해