이 글은 제가 타입챌린지를 하면서 해석한 내용을 적는 글입니다. 틀린 내용이 있으면 댓글 달아주시면 감사하겠습니다.
자바스크립트의 Object.entries를 구현하는 타입이다.
자바스크립트에서 Object.entries(obj) 를 실행하면, obj안에 있는 key와 value 값이 Array 형태로 리턴된다.
내가 처음으로 작성한 답이다.
type ObjectEntries<T> = keyof T extends infer P ? P extends keyof T ?
[P, T[P]] : never : never
keyof T extends infer P ? P extends keyof T ? : T의 key값이 P라면,
[P, T[P]] : never : never : [P, T[P]]인 배열을 리턴하고 아니라면 never를 리턴한다.
하지만, 이렇게 풀 경우 두번째 케이스인 ObjectEntries<Partial<Model>>, ModelEntries>를 만족하지 못한다.
그래서 UnPartial이라는 타입을 만들어 Partial타입일 경우 Optional을 해제하도록 코드를 변경했다.
type UnPartial<T> = {
[P in keyof T]-? : T[P]
}
type ObjectEntries<T> = keyof T extends infer P ? P extends keyof T ? [P, UnPartial<T>[P]] : never : never
하지만 이렇게 할 경우 세 번째 케이스인 ObjectEntries<{ key?: undefined }>, ['key', undefined]>를 만족하지 못한다...
결국엔 이 문제는 UnPartial을 어떻게 구현하냐의 문제다.
간단하다.
type UnPartial<T> = Omit<{
[P in keyof T as T[P] extends undefined ? never : P]-? : T[P]
} & {
[P in keyof T as T[P] extends undefined ? P : never] : T[P]
}, never>
type ObjectEntries<T, U = UnPartial<T>> = keyof U extends infer P ?
P extends keyof U ? [P, U[P]] : never : never
/* _____________ Test Cases _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
interface Model {
name: string
age: number
locations: string[] | null
}
type M = Partial<Model>
type ModelEntries = ['name', string] | ['age', number] | ['locations', string[] | null]
type cases = [
Expect<Equal<ObjectEntries<Model>, ModelEntries>>,
Expect<Equal<ObjectEntries<Partial<Model>>, ModelEntries>>,
Expect<Equal<ObjectEntries<{ key?: undefined }>, ['key', undefined]>>,
Expect<Equal<ObjectEntries<{ key: undefined }>, ['key', undefined]>>,
]
UnPartial
UnPartial을 undefined이 타입이 원래 리턴값인 속성과, 아닌 속성을 구분하여 주면 된다.
[P in keyof T as T[P] extends undefined ? never : P]-? : T[P] : 원래 리턴값이 undefined이 아닌 속성만 Optional을 없애고 리턴한다.
[P in keyof T as T[P] extends undefined ? P : never]: T[P] : 원래 리턴값이 undefined인 속성만 그대로 리턴한다.
그리고 Omit으로 합쳐준다.
ObjectEntries
type ObjectEntries<T, U = UnPartial<T>> : ObjectEntries 타입을 지정하는데, U를 T의 UnPartial타입으로 지정한다.
keyof U extends infer P ? P extends keyof U ? : U의 key값을 P라고 하면
[P, U[P]] : never : never : [P, U[P]]를 리턴하고 아니라면 never를 리턴한다.
'Language > Typescript' 카테고리의 다른 글
타입챌린지 : 3188-Tuple to Nested Object (medium) (0) | 2023.05.23 |
---|---|
타입챌린지 : 3062-Shift (medium) (0) | 2023.05.22 |
타입챌린지 : 2852-OmitByType (medium) (0) | 2023.05.20 |
타입챌린지 : 2793-Mutable (medium) (0) | 2023.05.18 |
타입챌린지 : 2759-RequiredByKeys (medium) (0) | 2023.05.14 |