컨디셔널 타입과 함께 사용, 추론하려는 부분을 infer로 만들면 됨
파라미터도 모르는 상태니 제너릭으로, infer E라는 변수로 알아서 추론해서 배열의 원본타입을 얻도록 해줌.
타입변수처럼 사용하게 해주는 기능임, Parameter, Return type등을 추론할 때 사용함.
type El<T> = T extends (infer E)[] ? E : never; //E가 타입변수
type Test<T> = T extends any[] ? T : never; //E가 타입변수 배열이 있을 때 배열의 요소타입을 얻냄
type Str = El<string[]> // string
type test2 = Test<string[]>; // string[] 타입..!! => 새로운 변수 도입해야함..
예시 2
함수 타입을 입력으로 받아서 반환타입을 추출하는 type임!! infer 키워드는 추론이 필요한 곳에서 선언할 것
type ReturnTypeOfFunction<T> = T extends (...args: any[]) => infer R ? R : never;
function greet(name: string): string {
return `Hello, ${name}!`;
}
type GreetReturnType = ReturnTypeOfFunction<typeof greet>; // string
type MyParameters<T> = T extends (...args: infer P) => any ? P : never; // Parameter 뽑아내는 fn
type MyPAndR<T> = T extends (...args:infer P) => infer R ? [P,R] : never;
type PR = MyPAndR<(a:string, b:number) => string>;
같은 이름의 타입변수를 여러곳에 사용 할 수 있음. 기본적으로 반환값일 때, 같은 이름의 타입변수는 union이 되지만, 매개변수일 경우 intersetion이 됨.
동시에 2가지를 만족시켜야하므로 => union type
하나의 매개변수를 넣었을 때 2가지를 모두 만족시켜야 하므로 => intersection type
type Union<T> = T extends {a: infer U, b: infer U} ? U : never;
type Result1 = Union<{a : 1|2 , b: 2|3}>
type intersection<T> = T extends {
a : (pa : infer U) => void,
b : (pb : infer U) => void
} ? U : never;
type Result2 = intersection<{a: (pa: 1|2)=> void, b: (pb:1|3)=>void}
typeof 연산자 이외에도 여러가지 사용가능.
undefined, null도 활용할 것. typeof null 은 object이므로 직접 거를때는 동등비교를 통해 null을 구분
배열 => Array.isArray함수 사용가능, class => instanceof 연산자 활용가능.
in 연산자를 통해 속성이 있는지 확인여부로 구분 가능
type을 구분하는 브랜드속성 사용가능
서술타입 존재
type안에서 자기자신을 참조하는 type임
원시 타입의 경우 해당 원시 타입을, 배열의 경우 원소의 타입을 얻는 유틸 함수를 작성한다면 다음과 같이 작성해볼 수 있다. (배열의 인자 타입으로 number를 넣으면 원소의 타입을 얻을 수 있다. index의 타입이 number 이기 떄문에)
타입인수로 사용하는 것은 불가능함.=>타입인수가 아닌 방향으로 수정
type ElementType<T> = T extends any[] ? ElementType<T[number]> :T;
type Result1 = ElementType<number[]>; //number
// T=string[], Result = string
// T=number[], Result = number
type T = number | string | Record<string,T> // refer itself
type T = number | string | {[key:string] : T}; // 타입인수를 쓰지 않으면 가능함.
특수한 문자열 타입임. 값 대신 타입을 만들기 위해 사용함.
타입의 조합에서 편의성이 존재함 아래와 같은 코드에서 type이 추가된다면, City와 Vehicle에 타입을 각각 넣어주면 됨
이게 조합형태로 만들때 사용함 => 3x3 이런식으로
템플릿리터럴 타입은 재귀호출이 가능함!
type City = "seoul" |"suwon"|"busan";
type Vehicle = "car" | "bike" | "walk";
type Id = `${City}:${Vehicle}`; //3x3타입을 자동생성해줌
type RemoveX<Str> = Str extends `x${infer Rest}` ? RemoveX<Rest> : Str extends `${infer Rest}x` ? RemoveX<Rest> : Str; // 재귀호출타입
type Removed = RemoveX<"xxtestxx">
타입주장은 변수에 적용해야만 타입이 유지됨.
조건절에서 error를 타입 assertion해도 조건절을 빠져나오면 TS는 이를 판단하지 못함. (조건절에서만 일시적으로 사용하기 때문.)
try{}
catch(error){
if(error){
error.message;
} // error => unknown type, if문을 통과하면 {} 타입이됨.
}
{
try{}
catch(error){
if(error as Error){
error.message;
} // error => unknown type, if문을 통과하면 {} 타입이됨.
}
}
try{}
catch(error){
const err = error as Error ;
if(err){
err.message;
} // 변수활용코드
}
try{}
catch(error){
if(error instanceof Error){
error.message;
} // instanceof 연산자 활용
}