interface Array<T> {
foreach(callbackfn: (value:T, index:number, array:T[]) => void, thisArg?:any
: void}; //T들이 같이 타입으로 정해짐
[1,2,3].forEach((value)=> value);
['1','2','3'].forEach((value)=> value);
// 각각 타입을 안써도 제네릭으로 인하여 타입을 알아챈다.
//Array<number|string|boolean> 이렇게 쓰면 안되나?
//그러면 타입이 다른 애들에 대한 처리가 달라진다 ex)add('1',2)
interface Arr {
forEach(callbackFn:(item:number|string)=>void):void;
}
const a:Arr = [1,2,3];
a.forEach((item)=>console.log(item))
const b:Arr = ['1','2','3'];
b.forEach((item)=>console.log(item))
interface Arr<T> {
forEach(callbackFn:(item:T)=>void):void;
}
const a:Arr<number> = [1,2,3];
a.forEach((item)=> item.toFixed(1))
const b:Arr<string> = ['1','2','3'];
b.forEach((item)=>console.log(item))
map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[];
[1,2,3].map((value)=> value.toString());
//결과가 string으로 변하기에 유추하면 U는 string
연습(만들기)
interface Arr<T> {
//interface Arr<T,S>는 못한다
//S에 타입을 지정해버리면 다른 타입에 해당되는 함수를 사용하지 못함
//그래서 map을 사용할 때, S 제네릭을 추가하여 새로운 것을 받도록
map<S>(callback:(v:T,i:number)=> S):S[];
}
const a:Arr<number> = [1,2,3];
const b = a.map((item)=> item+1)
const c = a.map((v)=> v.toString());
위치 주의
형식 조건자여야한다 === 커스텀 타입가드여야함
//1번 인터페이스
filter<S extends T>(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[];
//2번 인터페이스
filter(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): T[];
filter<S extends T>(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[];
//제네릭으로 타입을 지정하거나 커스텀 타입 가드하면 S에 대한 지정이 한번 더 들어감
filter(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): T[];
//데이터가 [1,2,'3',4,'5']이렇게면 T에 (string|number[])로 들어가게 됨
//1번 예제
const filtered1 = ['1',2].filter((value)=>typeof value === 'string');
=> 이렇게 하면 문제없음, 타입추론이 정확히 되지 않지만 2번 인터페이스 사용
=> 타입은 이렇게 됨 const filtered1: (string | number)[]
//2번 예제
const filtered2 = ['1',2].filter<string>((value)=>typeof value === 'string');
=> <string>으로 선언한 순간 1번 인터페이스를 따라야함
=> 콜백함수의 반환 타입을 명시해야함
//3번 예제 (2번 예제 개선)
const filtered3 = ['1',2].filter<string>((value): value is string => typeof value === 'string');
=> 타입가드로 반환 타입 지정해줘야함
return 값 - 넓은 타입으로 대입됨
function a(x:string) : number {
return +x
};
type B = (x:string) => number|string;
const b:B = a //가능
//return값은 더 넓은 타입으로 대입이 가능하다
function a(x:string) : number|string {
//(x:string)=>string되는 경우가 있기에
return +x
};
type B = (x:string) => number;
const b:B = a //가능
//b('abc') B타입에서 문제없음
//b(123)
//return값은 더 넓은 타입으로 대입이 불가
매개변수 : 좁은 타입으로 대입됨
function a(x:string|number) : number {
//(x:string)=> number 또는 (x:number) => number
//매개변수는 위와 같이 생각하면 안됨
//x:string|number 이 둘을 하나로 봄, 매개변수는 좁은 타입으로 대입됨
return 0
};
type B = (x:string) => number;
const b:B = a //가능
filter처럼 타이핑 한가지 방식 못하겠다 싶을때
여러가지 케이스 써서 오버로딩하면 됨
interface Add{
{x:number, y:number} : number;
{x:string, y:string} : string;
}
const add: Add = (x:any, y:any)=> x+y;
//any써도 됨, 오버로딩에서 알아서 걸러서 씀
interface CustomError{
name: string;
message: string;
stack?: string;
response?: {
data: any;
}
}
try{...}
catch(error){
if(error instanceof CustomError){
const customError = error as CutomError;
console.error(customError.response?.data};
customError.response?.data
}
//customError로 안만들면 사용할 때마다
//error as CutomError 사용해야함
}
//여기서 instanceof CustomError를 사용할때,
//interface가 js에서 사라지면서 CustomError를 못찾음
//그럴때, js에서도 남아있으면서 인터페이스랑 비슷한 역할을 해주는 것이 class
class CustomError extends Error{
response?: {
data: any;
}
}
//error instanceof CustomError일때는 타입가드로 좁혀졌기에
//const customError = error as CutomError안써도 됨