Total Typescript - infer

김동하·4일 전
0

typescript

목록 보기
14/17
post-thumbnail

1. infer basic

infer는 타입스크립트의 조건부 타입(Conditional Types)과 함께 사용되어 특정 타입을 추론할 수 있는 기능을 가진다.

평소에 infer만 보면 쫄았는데, infer가 무엇인지 확실히 알아보자.

문제

이런 귀여운 녀석이 있다. GetDatValue는 말그대로 data 하위 객체 정보를 타입으로 가져오는 역할을 한다.

예를들어 {data: "hello"} 일때, 추출된 타입이"hello"를 충족시키고 싶다. 그럼 테스트를 만족시키면서 타입을 정해보자

해결

가장 간단하게는 extends를 사용하여 { data : any} 를 확인하는 방법이 있을 수 있다.

이것도 좋지만 여기서 infer를 사용하면 좀 더 명확해진다.

infer로 추론되는 TData는 조건식 스코프에서만 작동한다.

가령 삼항식에 false 부분에 TData 를 두면 스코프 에러가 나온다.

infer with interface

그럼, interface를 사용하는 경우에서 infer를 알아보자.

다음과 같은 MyComplexInterface 라는 인터페이스가 있다. 위와 같은 상황에서 getPoint의 타입만 추출하고 싶다면 어떻게 해야할까?

해결

GetPoint를 extends하여 손봐보도록하자.

먼저 GetPointMyComplexInterface를 extends하여 조건부로 만든다.

any로 추론되고 있다. 4번째 항에 {x: 12, y: 14}를 추론하고 싶으니 무언가를 해줘야 한다.

ReturnType과 인덱스 타입을 적용하면

원하는 타입을 추론할 수 있다.

하지만, 이것으로는 부족하다. infer를 사용하여 제네릭하게 변경해보자.

아주 추론이 잘 되고 있다. infer와 조금 가까워진 것 같다

2. infer advanced

infer with template literal

그럼 infer로 어디까지 할 수 있는지 보자..

tuple 형태의 Names와 성만 추출하는 GetSurname이라는 타입이 있다.

GetSurname 통해서 성만 추출하는 타입을 작성해보자.

일단 조건식은 대략 이럴 것이다. 이제 "이름 성" 으로 이루어져있는지 확인을 하고 그렇다면 성을 반환하도록하면 된다.

여기서 template literalinfer가 쓰인다.

${infer First} ${infer Last} 이부분을 template literal로 형태를 잡아주고 infer로 추론하는 것이다

모든 테스트가 다 통과된다.

(아니 infer로 이거까지 한다고...? )

infer return type

그럼 이제 좀 더 실무적인 예제를 보자.

서버사이드에서 호출하는 api가 있다고 가정하자.

이제 InferPropsFromServerSideFunction을 통해 함수의 props 리턴 타입을 추출해보자.

처음엔 이런 형태로 작성할 수 있을 것이다. () => Promise<any>로 확장하여 any 를 반환한다.

이제 여기에 props를 infer 한다.

테스트를 통과했다.

infer in union

갈 때까지 간 infer의 마지막 예제다

다양한 형태의 파싱 함수가 있다.

GetParserResult라는 하나의 유틸 함수를 사용하여 각 함수의 리턴값을 추출하는 것

먼저 노가다와 삼항으로 이렇게 작성할 수 있겠다. 모든 경우를 조건부에 적용시켰다.
하지만 가독성이 매우 떨어진다. 이것을 조금 이쁘게 리팩토링해보자. 이때 union을 활용하면 된다.

3가지 타입 형태를 유니언으로 두고, 삼항을 사용하여 infer한 것

테스트는 모두 통과된다!

Distributive Conditional Types

이제 마지막이다!! infer 정말 많이 쓰이는구나

Fruit 이라는 유니언 타입이 있다.

여기서 특정 타입만 골라서 새로운 타입을 만들고 싶을 때면 유니언을 extends해서 사용하면 될까?

AppleOrBanna의 타입이 never가 나와버린다.

이유인즉슨, Fruit 타입 전체('apple' | 'banana' | 'orange')가 'apple' | 'banana'의 서브타입인지 검사하기 때문이다.

여기서 분배 조건부 타입(Distributive Conditional Types)으로 해결할 수 있다.

타입스크립트에서 제네릭을 사용하게 되면 T를 분리하여 유니언 개별 타입에 적용한다.

개별 타입에 대한 T이므로 삼항은 정상 동작하게 된다.

(AppleOrBanna에서 GetAppleOrBanna로 변수명 변경)

이제 타입이 제대로 작동하는 것을 확인할 수 있다.

infer

여기서 제네릭을 사용하지 않고 infer를 사용해서도 가능하다.


(거의 포기)

Fruit extends infer TFruit 유니온 타입('apple' | 'banana' | 'orange')을 infer T로 분배한다.

제네릭으로 했던 것과 동일하게 T extends "apple" | "banana"에서 개별 타입으로 검사한다.

이렇게 되면 동일하게 타입이 작동한다. (오늘 ts 여기까지...)

참고 : total typescript

profile
프론트엔드 개발

0개의 댓글

관련 채용 정보