[TypeScript] 형지옥에서 싸우는 정규 노트.
유니버설 전환의 필요성
TypeScript를 사용하여 몰드를 처리할 때는 지정된 데이터 구조를 재구성하여 새 구조를 만들고 값을 반환해야 합니다.만약 이것이 변하지 않는 구조라면, 물론 매번 수동으로 정의해도 문제없다.그러나 API를 만들 때 대응하는 도구가 자동으로 생성하는 유형은 매우 힘들다.이런 상황에서 유니버설 구조를 만들 수 있다면 자동으로 생성되는 유형에 대응할 수 있다.이때의 장르 정의 정석을 소개해 드리도록 하겠습니다.
Generics 및 Type
type의 일반적인 사용 방법을 아는 것으로 추진하다.Type에서 Generics를 사용하고 extends에서 유형 변환을 할 때 다음과 같이 쓴다
type タイプ名<型変数 extends 制約,...> = 型変数 extends 条件 ? 真の型 : 偽の型
=
이전extends
과 이후extends
에서는 의미의 차이에 주의해야 한다.전자는 유형을 사용할 때 틀린 쪽이 들어갈 때 문법 오류가 발생한다.후자는 조건에 따라 반환자가 의견 차이를 일으키는 것이다.Generics에 등장하는 infer
type タイプ名<型変数 extends 制約,...> = 型変数 extends 条件(infer 取り出し変数) ? 真の型(取り出した変数が使用可能) : 偽の型
infer
이후에 예를 들어 설명하지만 조건의 일부분으로 편입하면 이 부분만 추출할 수 있다구체적 예
조건에 따라 분류하다
type Test01<T> = T extends string ? number : boolean;
이것을 사용하면 다음과 같다.type Test01A = Test01<string>; //number
type Test01B = Test01<object>; //boolean
type Test02<T> = T extends unknown ? number : boolean;
extends의 조건으로any와unknown(대상은never 이외)을 사용하면 조건을 강제로 성립시킬 수 있다.이를 사용하는 경우 기존 유형과 상관없이 구조 재편을 진행하는 경우다.사용 예는 다음과 같다.
type Test02A = Test02<string>; //number
type Test02B = Test02<object>; //number
특정 부분 제거
interface TestIF01 {
a: { a0: number };
b: { b0: number };
}
type Test03<T> = T extends { a: infer R } ? R : never;
대상에서 a의 유형을 추출하고 존재하지 않으면never로 되돌려줍니다type Test03A = Test03<TestIF01>; //{a0:number}
type Test03B = Test03<{}>; //never
type Test04<T> = T extends { [_ in keyof T]: infer R } ? R : never;
대상에서 키 부분을 꺼내려면 키of를 사용할 수 있지만,valueof와 같은 키워드는 존재하지 않기 때문에 위와 같이 설명해야 한다.객체 키를 결정하지 않고 컨텐트를 체크 아웃하는 경우
{[キー変数 in keyof キー型]:値}
이런 작법.type Test04A = Test04<TestIF01>; //{a0:number} | {b0:number}
키를 지정하지 않고 객체 컨텐트를 체크 아웃하면 공통 쉐이프가 됩니다.결과가 교차형일 가능성도 있기 때문에 다음 항목에서 방법을 소개한다.공통 체형을 교차형으로 바꾸다
type Test05<T> = (T extends any ? (_: T) => void : never) extends (
_: infer R
) => void
? R
: never;
입력한 유형을 함수 매개 변수로 변환한 후 공용체형을 교차형으로 변환한다.type Test05A = Test05<Test04A>; //{a0:number} & {b0:number}
{a0:number} | {b0:number}
를 {a0:number} & {b0:number}
로 전환하는 중간 과정은 다음과 같다.(_:{a0:number})=>void | (_:{b0:number})=>void
단일 매개 변수가 아니라 함수는 공용 체형이다.아니오
(_:{a0:number} | {b0:number})=>void
,주의하세요.여기서 매개 변수의 유형을 선택하면 함수의 조건이 성립되는 것은 교차형의 대상이 되는 원리이다.빙빙 돌기는 했지만 조합 전환 기능이 없어 이렇게 쓸 수밖에 없었다.
구조를 정돈하다
interface TestIF02 {
200: { token: string };
500: { err: string };
}
위의 인터페이스는 RestAPI 관련 도구를 통해 자동으로 출력되는 간단한 예입니다.type Test06<T> = T extends unknown
? { [M in keyof T]: { code: M; value: T[M] } } extends {
[_ in keyof T]: infer R;
}
? R
: never
: never;
{code:コード,value:値}
의 형식으로 변환type Test06A = Test06<TestIF02>;
//{code:200,value:{token:string}} | {code:500,value:{err:string}}
공용체형으로 이러한 구조를 만들면 코드 값을 판정할 때value 유형을 결정하는 논리를 사용할 수 있다if(result.code === 200){
result.value //{token:string}が確定
}else{
result.value //{err:string}が確定
}
복잡화 유형 변환
이번에 소개한 것은 type의 전환 예로 도대체 입문 수준일 뿐이라고 한다.Generics를 함수 매개 변수 등으로 설정하여 제한하거나 반환값 변환 등을 진행할 때 변환 절차가 커집니다.
다음은
openapi-typescript
의 패키지에서 토출된 RestAPI의 유형 데이터를 활용하여 매개변수와 반환 값을 생성한 예입니다.실제 동작은 그리 대단한 일은 아니지만 금형을 조립하는 작업은 대부분의 비용을 들인다.import { paths } from '@/types/api'
const baseURL = process.env.NODE_ENV === 'development' ? 'http://localhost:4010' : '/api'
export const requestApi = <
T extends paths,
path extends keyof T,
method extends keyof T[path],
body extends T[path][method] extends { parameters: { body: { [key: string]: infer R } } }
? R
: never,
response extends T[path][method] extends { responses: infer res }
? {
[P in keyof res]: {
code: P
body: res[P] extends { schema: infer R } ? R : res[P]
}
} extends {
[P in any]: infer R
}
? R
: never
: never
>(
method: method,
path: path,
body?: body,
token?: string
): Promise<response> => {
return fetch(baseURL + path, {
method: method as string | undefined,
headers: {
'Content-Type': 'application/json',
...(token ? { Authorization: `Bearer ${token}` } : {})
},
body: body && JSON.stringify(body)
}).then(
async (res) =>
({
code: res.status,
body: await res.json()
} as response)
)
}
총결산
퍼즐 맞추는 거 재밌어요.
Reference
이 문제에 관하여([TypeScript] 형지옥에서 싸우는 정규 노트.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/sora_kumo/articles/7e59942b952b27텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)