
interface Arr<T> {
map():void
}
const a: Arr<number> = [1,2,3,4]
const b = a.map(v => v+1)
처음 map을 간단한 형태로 선언한다.
변수 b 가 void가 아니기 때문에 map의 파라미터에 들어갈 callback 값을 정의해준다
interface Arr<T> {
map(callback: (v: T) => void):void // <--변경
}
const a: Arr<number> = [1,2,3,4]
const b = a.map(v => v+1)
여기서 변수 b의 타입은 void로 나오는데 map의 리턴값을 정의해주자
interface Arr<T> {
map<S>(callback: (v: T) => S): S[] // <--변경
}
실제 lib.es5.d.ts에서의 map의 타입과 비교해보자
map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[];
map<S>(callback: (v: T) => S): S[]
두번째, 세번째 파라미터를 제외하면 callback fn의 타입은 정확히 일치한다
const a = [1,2,3,4,'5'].filter((v) => typeof v === 'string')
여기서 변수 a는 (string | number)[]로 타입이 추론된다. 당연히 예상컨데 string[]으로 나와야할 것 같지만 아니다.
이걸 좀 더 정확하게 타이핑하려면 어떻게 해야할까?
filter에 선언된 타입을 살펴 보자
// lib.es5.d.ts
/**
* Returns the elements of an array that meet the condition specified in a callback function.
* @param predicate A function that accepts up to three arguments. The filter method calls the predicate function one time for each element in the array.
* @param thisArg An object to which the this keyword can refer in the predicate function. If thisArg is omitted, undefined is used as the this value.
*/
filter<S extends T>(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[];
/**
* Returns the elements of an array that meet the condition specified in a callback function.
* @param predicate A function that accepts up to three arguments. The filter method calls the predicate function one time for each element in the array.
* @param thisArg An object to which the this keyword can refer in the predicate function. If thisArg is omitted, undefined is used as the this value.
*/
filter(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): T[];
첫번째 predicate callback을 보면 value is S 로 타입가드가 되어 있다. 이를 통해 해결할 수 있다
const a = [1,2,3,4,'5'].filter((v): v is string => typeof v === 'string')