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의 반환 타입의 서브타입)