과거 프로그래밍 자료들/Javascript&typescript
[TS] forEach, map, filter 제네릭 분석
평부
2022. 9. 16. 16:52
출처 : https://github.com/ZeroCho/ts-all-in-one
* forEach, map, filter에 대한 interface<T> 부분
https://github.com/microsoft/TypeScript/blob/main/lib/lib.es5.d.ts
제네릭에 대해 타입을 변수처럼 만든다는 것은 알겠음
▶ 실제로는 어떻게 이용되는 것인가?
* forEach
//forEach
[1,2,3].forEach((item) => {console.log(item)}); //1 2 3
//item : number로 표시됨
[1,2,3].forEach((item) => {console.log(item)});
//item : string로 표시됨
['1','2','3'].forEach((item) => {console.log(item)});
//item: boolean으로 표시됨
[true,false,true].forEach((item) => {console.log(item)})
//위의 forEach 예제들의 item의 값들이 저렇게 표시되는 이유 : 제네릭 덕분(JS에서는 사라짐)
interface Array<T> {//T자리에 뭐가 올지 모름(자리만 만듦)
forEach(callbackfn: (value: T, index: number, array: T[]) => void, thisArg? :any): void
}//하나가 정해지면 나머지도 숫자, 문자열로 따라감
//콜백함수 : callbackfn: (value: T, index: number, array: T[]) => void == 위의 forEach 예제들의 (item) => {console.log(item)}
//value = 위의 forEach 예제들의 item
* 그런데 꼭 제네릭을 써야 하나? 그 자리에 해당되는 값들만 넣어주면 되지 않나?
▶ 그럴 경우 생기는 문제 : 여러 타입이 존재 시 같은 타입들만 사용하는 게 아니라 다른 타입인데도 같이 사용되는 오류들 발생
function add(x: string | number, y: string | number) {}
add(1, '2') //오류도 맞다고 표시됨
add('1', 2) //오류도 맞다고 표시됨
//위의 사례를 막고 타입이 일치하는 것들만 가능하도록 하게 함 = 제네릭 사용
add(1, 2)
add('1', '2')
add(true, false)
//여러 T 중 하나라도 타입이 정해지면 다른 것들도 동일하다고 생각함
function add<T>(x: T, y: T): T {return x}
add(1, 2) //x가 number면 y도 number로 생각함
//타입 파라미터 : add<number>(1, 2)도 가능함
add('1', '2') //x가 string이면 y도 string으로 생각
* map
//map
interface Array<T> {
map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg? :any): U[]
}
//const strings = string[] 추론
//예시
const strings = [1, 2, 3].map((item) => item.toString())
//위의 Array<T> = 예시의 number, 위의 U = 예시의 item.toString() => string값
//따라서 map 함수의 전체 리턴값 string[]
* filter
interface Array<T> {
filter<S extends T>(predicate: (value: T, index: number, array: readonly T[]) => value is S, thisArg?: any): S[];
filter(predicate: (value: T, index: number, array: readonly T[]) => unknown, thisArg?: any): T[];
}
//const filtered = number[]
const filtered = [1, 2, 3, 4, 5].filter((value) => value %2);
//T는 number, S도 number
//value % 2 = number
//filtered는 number[]
//문제
//string[]이어야 하는데 (string | number)[]로 나옴
const filtered2 = ['1', 2, '3', 4, '5'].filter((value) => typeof value === "string");
//T는 string | number, S는 string | number 결과도 string | number
//string[]만 나오게 하려면?
//(predicate: (value: T, index: number, array: readonly T[]) => value is S, thisArg?: any)
const predicate = (value: string | number): value is string => typeof value === "string";
const filtered3 = ['1', 2, '3', 4, '5'].filter(predicate);
////number[]만 나오게 하려면?
const checkNum = (value: string | number): value is number => typeof value === "number";
const filtered4 = ['1', 2, '3', 4, '5'].filter(checkNum);