Typescript 객체 리터럴 배열에서 무차별 유니온 객체 유형 가져오기

때로는 유형이 없지만 배열 값이 있고 요소 유형을 얻고 싶습니다.

const obj = [{size:"big", color:"blue"},{size:"small", color:"red"}]


요소 유형을 얻으려면 이렇게 할 수 있습니다. 먼저 배열을 const로 주장한 다음

const colorAndSize = [{size:"big", color:"blue"},{size:"small", color:"red"}] as const

type ColorAndSize = typeof colorAndSize //[{ readonly size: "big"; readonly color: "blue";}, { readonly size: "small"; readonly color: "red";}]

type DeepMutable<T> = { -readonly [P in keyof T]: DeepMutable<T[P]> } // remove readonly modifier

type GetElementType<T extends readonly Record<string, unknown>[]> = DeepMutable<T[number]> // { size: "big"; color: "blue";} | { size: "small"; color: "red";}

const abc:GetElementType<ColorAndSize> = {size:"big", color:"blue"} // ok

const efg:GetElementType<ColorAndSize> = {size:"big", color:"red"} // error


playground

우리는 차별적인 결합으로 끝나고 유형을 혼합할 수 없기 때문에 이상적이지 않을 수 있습니다. 예를 들어 우리는 크고 빨간색을 가질 수 없습니다.

무차별 합집합을 계산하는 방법은 다음과 같습니다.

const colorAndSize = [{size:"big", color:"blue"},{size:"small", color:"red"}] as const

type ColorAndSize = typeof colorAndSize //[{ readonly size: "big"; readonly color: "blue";}, { readonly size: "small"; readonly color: "red";}]

type DeepMutable<T> = { -readonly [P in keyof T]: DeepMutable<T[P]> }; // remove readonly modifier

type GetUndiscriminatingElement <T extends Record<string,unknown>[], U extends T[number]=T[0]>= T extends [infer H, ...infer Rest]?
  Rest extends []?{[key in keyof H]:U[key extends keyof U ? key:never]|H[key]}
  : Rest extends Record<string,unknown>[]?GetUndiscriminatingElement<Rest,{[key in keyof H]:U[key extends keyof U ? key:never]|H[key]}>:"impossible route"
:"impossible route"

type A =  GetUndiscriminatingElement<DeepMutable<ColorAndSize>> // { size: "big" | "small"; color: "blue" | "red";}

const a:A = {size:"big", color:"red"} // ok



playground

제한: TS 재귀의 최대 깊이가 1000이기 때문에 배열의 길이는 999를 초과할 수 없습니다.

업데이트: 덕분에 더 간단하고 재귀 깊이에 제한을 받지 않습니다.

const colorAndSize = [{size:"big", color:"blue"},{size:"small", color:"red"}] as const

type ColorAndSize = typeof colorAndSize //[{ readonly size: "big"; readonly color: "blue";}, { readonly size: "small"; readonly color: "red";}]

type GetUndiscriminatingElement <T extends readonly Record<string,unknown>[]> = 
{ -readonly [P in keyof T]: T[P] } extends [infer H,...infer Rest] 
  ? { -readonly [Key in keyof T[number]]: T[number][Key]} 
  : "you forgot to assert as const"

const A :GetUndiscriminatingElement<ColorAndSize> = {size:"big", color:"red"} // ok


playground

좋은 웹페이지 즐겨찾기