O
& O1
의 차이점인 객체
를 가져옵니다
예시
import type { Equal, Expect } from "@type-challenges/utils";
type Foo = {
name: string;
age: string;
};
type Bar = {
name: string;
age: string;
gender: number;
};
type Coo = {
name: string;
gender: number;
};
type cases = [
Expect<Equal<Diff<Foo, Bar>, { gender: number }>>,
Expect<Equal<Diff<Bar, Foo>, { gender: number }>>,
Expect<Equal<Diff<Foo, Coo>, { age: string; gender: number }>>,
Expect<Equal<Diff<Coo, Foo>, { age: string; gender: number }>>,
];
접근 방식
코드
type GetDiff<A, B> = { [K in keyof A]: A[K] extends B ? A[K] : never };
type Diff<O, O1, DiffIntersection = GetDiff<O, O1> & GetDiff<O1, O>> = {
[K in keyof DiffIntersection]: DiffIntersection[K];
};
type example1 = Diff<Foo, Bar>;
// { name: never; age: never; gender: never; }
실패 이유
key: never
로 처리됨접근 방식
코드
type GetDiff<A, B> = { [K in keyof A as K extends keyof B ? never : K]: A[K] };
type Diff<O, O1, DiffIntersection = GetDiff<O, O1> & GetDiff<O1, O>> = {
[K in keyof DiffIntersection]: DiffIntersection[K];
};
코드 설명
GetDiff
함수는 첫번째 인자의 키를 순회하며 두번째 인자에 포함되지 않는 키를 never
로 처리한 객체를 리턴DiffIntersection
은 GetDiff<A, B>
와 GetDiff<B, A>
의 유니온 객체DiffIntersection
의 키를 순회하며 각 키의 값을 리턴Python의 any
function을 타입 시스템으로 구현하세요
배열을 사용하고 배열의 요소가 참이면 true
를 반환합니다. 배열이 비어 있으면 false
를 반환합니다
예시
type Sample1 = AnyOf<[1, "", false, [], {}]>; // expected to be true.
type Sample2 = AnyOf<[0, "", false, [], {}]>; // expected to be false.
접근 방식
코드
type IsFalse = 0 | "" | false | [] | {} | undefined | null;
type AnyOf<T extends readonly any[]> = T extends []
? false
: T extends [infer First, ...infer Rest]
? First extends IsFalse
? AnyOf<Rest>
: true
: false;
실패 이유
IsFalse
에 들어있는 {}
가 모든 객체를 false로 잡아버림접근 방식
isEmptyObject
라는 타입을 만들어 빈 객체를 false로 처리하도록 변경코드
type IsEmptyObject<T> = keyof T extends never ? true : false;
type IsFalse<T> = T extends 0 | "" | false | [] | undefined | null
? true
: T extends object
? IsEmptyObject<T>
: false;
type AnyOf<T extends readonly any[]> = T extends []
? false
: T extends [infer First, ...infer Rest]
? IsFalse<First> extends true
? AnyOf<Rest>
: true
: false;
코드 설명
IsEmptyObject
는 keyof T
가 never
(키가 존재하지 않는 빈 객체)일 경우 true를 리턴하는 타입IsFalse
는 비어있는 배열, 0, "", false, undefined, null, 그리고 빈 객체를 true로 처리하는 타입AnyOf
는 빈 배열일 경우 false를 리턴IsFalse
타입이 false 값을 가질 경우 false 리턴input type으로 T
를 받는 IsNever type을 구현하세요. 만약 T
의 유형이 never
으로 확인되면 true
를 반환하고 아니면 false
를 반환합니다
예시
type A = IsNever<never>; // expected to be true
type B = IsNever<undefined>; // expected to be false
type C = IsNever<null>; // expected to be false
type D = IsNever<[]>; // expected to be false
type E = IsNever<number>; // expected to be false
접근 방식
T
가 never
일 경우 true
를 리턴하고 아니면 false
를 리턴코드
type IsNever<T> = [T] extends [never] ? true : false;
코드 설명
[T] extends [never]
은 T
가 never
일 경우 true
를 리턴하고 아니면 false
를 리턴(분배법칙 X)T
를 입력으로 받고, T
가 Union
유형으로 확인되는지 여부를 반환하는 IsUnion
을 구현하세요
예시
type case1 = IsUnion<string>; // false
type case2 = IsUnion<string | number>; // true
type case3 = IsUnion<[string | number]>; // false
접근 방식
코드
type UnionToTuple<T, K = T> = [T] extends [never]
? []
: K extends K
? [K, ...UnionToTuple<Exclude<T, K>>]
: never;
type IsUnion<T> = UnionToTuple<T>["length"] extends [any] ? true : false;
type example = UnionToTuple<string | number | boolean>;
실패 이유
접근 방식
T
)과 같으면 false, 다르면 true코드
type IsUnion<T, U = T> = [T] extends [never]
? false
: T extends U
? [U] extends [T]
? false
: true
: never;
코드 설명
[T] extends [never]
은 T
가 never
인 경우 분기처리T extends U
를 활용해 각 요소를 순회(항상 참인 조건, 분배법칙만을 위한 요소)U
= 입력받은 T
)이 같다면 이는 유니온 타입이 아니기 때문에 false
를 반환true
를 반환Union type의 key를 대체하는 ReplaceKeys를 구현하세요.
만약 일부 유형에 해당 key가 존재하지 않는다면 대체하지 않습니다. 타입은 세 개의 인자를 받습니다.
예시
type NodeA = {
type: "A";
name: string;
flag: number;
};
type NodeB = {
type: "B";
id: number;
flag: number;
};
type NodeC = {
type: "C";
name: string;
flag: number;
};
접근 방식
코드
type ReplaceKeys<U, T extends keyof any, Y> = U extends U
? T extends T
? T extends keyof U
? T extends keyof Y
? Y[T]를 추가한 U
: never
: Record<T, never>를 추가한 U
: never
: never;
실패 이유
Y[T]를 추가한 U
, Record<T, never>
를 추가한 U를 구현할 방법을 못찾음접근 방식
코드
type ReplaceKeys<U, T extends keyof any, Y> = {
[K in keyof U]: K extends T ? (K extends keyof Y ? Y[K] : never) : U[K];
};
코드 설명
T
는 키값이므로 extends keyof any
로 선언K in keyof U
는 유니온 타입으로 묶인 각 객체들의 키들을 모두 순회K extends T
조건을 만족할 경우(T가 객체의 키 값일 경우), 다음 조건 확인K
가 Y
의 키 값일 경우, Y[K]
를 반환, 아닐 경우 never
를 반환K
가 T
의 키 값이 아닐 경우, U[K]
를 반환객체 유형에서 인덱스 시그니처를 제외하는 RemoveIndexSignature<T>
를 구현하세요
예시
type Foo = {
[key: string]: any;
foo(): void;
};
type A = RemoveIndexSignature<Foo>; // expected { foo(): void }
접근 방식
코드
type RemoveIndexSignature<T> = {
[K in keyof T as K extends [key: keyof any] ? never : K]: T[K];
};
실패 이유
[key: keyof any]
형태 걸러내기 실패접근 방식
코드
type RemoveIndexSignature<T, P = PropertyKey> = {
[K in keyof T as P extends K ? never : K extends P ? K : never]: T[K];
};
코드 설명
P
는 PropertyKey
로 선언P extends K
조건을 만족하는 경우, 해당 키 값을 제거P extends K
조건을 만족한다는 것은 K
가 P(string | number | symbol)
의 슈퍼타입이라는 것K
가 string
, number
, symbol
이면 never
을 반환하여 키를 삭제K extends P
조건을 만족하는 경우(K가 P의 서브타입일 경우, 예를 들어 'foo'
, 123
, symbol
등), K
를 반환하여 키를 유지PropertyKey 타입이란 무엇인가?
keyof any
와 같은 타입Index Signature란 무엇인가?