타입스크립트에서 객체 같은 interface도 있고, 함수와 같은 타입파라미터인 Generic도 있는데, 조건문이 없을까보냐 했는데
타입스크립트에서도 삼항연산자와 같은 문법이 존재한다
type A<T> = T
const a : A<string> = 'str'
이러면 A<string>
쓰면 string이 남는다.
( 타입변수에도 타입파라미터 넣기가 가능하다요 )
이걸 조건부로
" 타입파라미터 자리에 string 타입 집어 넣으면 string, 그게 아니면 전부 unknown을 "
if문을 써보자
타입 조건식은 주로 extends 키워드와 삼항연산자
를 이용한다고 하는데
" extends는 왼쪽이 오른쪽의 성질(조건)을 가지고(만족)하냐 " 라는 뜻으로 사용 할수 있기에 조건식 용도로 사용가능하다고 한다.
수학에서 사용하는 ⊂ 역할인듯 함
type A<T> = T extends string ? string : unknown;
let a : A<string> // a는 string 타입
let b : A<number> // b는 unknown 타입
" T라는 파라미터가 string 성질을 가지고 있냐? 그러면 string 아니면 unknown "
이라는 말을 코드로 타자 치면 저렇게 쓴다.
조금더 나아가서
Q . type parameter로 array 자료를 입력하면 array의 첫 자료의 타입을 남겨주고 array 타입이 아니면 unknown 타입을 남겨주는 조건부 타입은?
type A<T> = T extends any[] ? T[0] : unknown
다른 예시로 ( extends가 최소한을 만족한다라는 말을 이해하기 위해서 )
type B = {
length : number
}
type A<T> = T extends B ? T : any
let a :A<string[]> = ['asdf']; // a의 타입은 string[]
let b :A<number> = 1; // b의 타입은 any
조건문에서 사용할 수 있는 특별한 infer 키워드가 있다.
infer 키워드는 지금 입력한 타입을 변수로 만들어주는 키워드라고 하는데..
글 만 읽어보면 먼 말인지 모르니 예시를 보자
type Person<T> = T extends infer R ? R : unknown;
type NewType = Person<string> // NewTpye의 타입은 string
infer 키워드의 특징은
조건문안에서만 infer 키워드를 사용할 수 있다.
infer 우측에 자유롭게 작명해주면 타입을 T에서 유추해서 R 이라는 변수에 집어넣어주쇼 라는 의미
그래서 위의 예제에서 <string>
이렇게 타입파라미터자리에 string 집어넣으면 R은 string이 된다.
R을 조건식 안에서 맘대로 사용이 가능하다.
array 안에 있던 타입이 어떤 타입인지 뽑아서 변수로 만들 수 있다 .
type Abstract<T> = T extends (infer R) [] ? R : unknown;
type NewType = Abastract<boolean[]> // NewType은 boolean 타입
이런식으로 (infer R) [ ] 면 array가 가지고 있던 타입부분만 쏙 뽑아서 R 변수에 할당이 가능하다.
뭔가... 뽑기 같은데?
함수의 return 타입이 어떤 타입인지 뽑아서 변수로 만들어 줄 수 있다 .
type Abstract<T> = T extends ( () => infer R ) ? R : unknown;
type NewType = Abstract < () => number > // NewType은 number 타입
타입 파라미터에 <함수> 를 집어넣어 return 타입을 쏙 뽑아서 R이라는 변수에 담는 코드
그냥 infer를 사용하면 타입 추출이라고 이해하면 되겠다 .
위의 예제 처럼 거창할 필요없고
type 리턴타입 = ReturnType<()=>void> // 리턴타입은 void 입니다.
이게 더 좋을듯 함
타입파라미터로
1. array 타입 인데 튜플인 array임
2. array의 첫 타입이 string 이면 타입을 그대로 받고
3. array의 첫 자료가 string이 아니면 unknown을 남겨주려면?
let test1 : A<[string, number]> // string 타입
let test2 : A<[boolean,number]> // unknwon 타입
정답은
type A<T> = T extends [string,...any] ? T[0] : unknown