객체의 키와 값을 서로 바꾸는 타입을 구현하세요.
제약사항
예시
Flip<{ a: "x"; b: "y"; c: "z" }>; // {x: "a", y: "b", z: "c"}
Flip<{ a: 1; b: 2; c: 3 }>; // {1: "a", 2: "b", 3: "c"}
Flip<{ a: false; b: true }>; // {false: "a", true: "b"}
접근 방식
코드
type Flip<T> = { [K in keyof T as T[K] extends PropertyKey ? T[K] : never]: K };
실패 이유
접근 방식
PropertyKey
로 제한하는 대신, string
, number
, boolean
타입을 키 값으로 사용할 수 있도록 제한코드
type Flip<T> = {
[K in keyof T as T[K] extends string | number | boolean
? `${T[K]}`
: never]: K;
};
코드 설명
T[K] extends string | number | boolean
형태로 키 값을 제한숫자 T
를 입력받아 해당하는 피보나치 수를 반환하는 제네릭 타입 Fibonacci<T>
를 구현하세요.
수열은 다음과 같이 시작됩니다:
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...
예시
type Result1 = Fibonacci<3>; // 2
type Result2 = Fibonacci<8>; // 21
접근 방식
코드
type Fibonacci<
T extends number,
Fibo1 extends any[] = ["f"],
Fibo2 extends any[] = ["f"],
Count extends any[] = ["f", "f", "f"]
> = T extends 1 | 2
? 1
: Count["length"] extends T
? [...Fibo1, ...Fibo2]["length"]
: Fibonacci<T, Fibo2, [...Fibo1, ...Fibo2], [...Count, "f"]>;
코드 설명
T extends 1 | 2
형태로 초기 조건 설정(T
가 1, 2일 때 항상 1)T
가 3 이상일 때 Count
의 length
가 T
와 같아지면 앞의 두 배열을 합한 배열의 length
를 반환Count
의 length
가 T
보다 작으면, 뒤의 배열을 앞의 배열에 할당하고, 뒤의 배열은 앞의 배열과 뒤의 배열을 합친 배열을 할당Count
에 "f"
를 추가하여 재귀 호출문자열 S
의 문자들을 최대 한 번씩만 사용하여 만들 수 있는 모든 문자열 조합을 반환하는 AllCombinations<S>
타입을 구현하세요.
예시
type AllCombinations_ABC = AllCombinations<"ABC">;
// 결과값: '' | 'A' | 'B' | 'C' | 'AB' | 'AC' | 'BA' | 'BC' | 'CA' | 'CB' | 'ABC' | 'ACB' | 'BAC' | 'BCA' | 'CAB' | 'CBA'
접근 방법
코드
type StringToTuple<S extends String> = S extends `${infer First}${infer Last}`
? [First, ...StringToTuple<Last>]
: [];
type StringToUnion<S extends string> = StringToTuple<S>[number];
type Permutation<T extends string[], K = T> = [T] extends [never]
? []
: K extends K
? [K, ...Permutation<Exclude<T, K>>]
: never;
type Join<T extends string[]> = T extends [
infer First extends string,
...infer Rest extends string[]
]
? `${First}${Join<Rest>}`
: "";
type AllCombinations<
S extends string,
P = Permutation<StringToUnion<S>>
> = P extends P ? Join<P> : never;
코드 설명
StringToTuple
함수는 문자열을 튜플로 변환StringToUnion
함수는 튜플을 union으로 변환Permutation
함수는 주어진 배열의 순열을 생성Join
함수는 배열을 문자열로 결합실패 이유
Permutation
을 활용하면 안됨ABC
의 경우 ABC
, ACB
, BAC
, BCA
, CAB
, CBA
이렇게 6개의 요소만 확인 가능Exclude
를 활용해 접근하는 방식은 맞을 듯코드
type StringToUnion<S extends string> = S extends `${infer L}${infer R}`
? L | StringToUnion<R>
: S;
type Combination<A extends string, B extends string> =
| A
| B
| `${A}${B}`
| `${B}${A}`;
type UnionCombination<A extends string, B extends string = A> = A extends B
? Combination<A, UnionCombination<Exclude<B, A>>>
: never;
type AllCombinations<S extends string> = UnionCombination<StringToUnion<S>>;
코드 설명
StringToUnion
함수는 문자열을 union으로 변환 ('' 포함)Combination
함수는 두 문자열을 이용해 조합 생성UnionCombination
함수는 string union으로 들어온 A
를 순회하며, 각 요소와 해당 요소를 제외한 union을 재귀적으로 호출하여 조합 생성AllCombinations
함수는 UnionCombination
함수를 활용하여 모든 문자열 조합을 반환
StringToUnion
함수 구현 방식
type StringToUnion<S extends string> = S extends `${infer L}${infer R}`
? L | StringToUnion<R>
: S;
이 챌린지에서는 T > U와 같은 GreaterThan<T, U>
타입을 구현해야 합니다.
음수는 고려하지 않아도 됩니다.
예시
GreaterThan<2, 1>; //true가 되어야 함
GreaterThan<1, 1>; //false가 되어야 함
GreaterThan<10, 100>; //false가 되어야 함
GreaterThan<111, 11>; //true가 되어야 함
접근 방법
코드
type StringToTuple<S extends String> = S extends `${infer First}${infer Last}`
? [First, ...StringToTuple<Last>]
: [];
// N 크기의 unknown[] 생성
type BuildArray<
N extends number,
Arr extends unknown[] = []
> = Arr["length"] extends N ? Arr : BuildArray<N, [...Arr, unknown]>;
// T가 U 이상인지 확인(같거나 더 클 경우)
type CompareDigit<T extends number, U extends number> = BuildArray<T> extends [
...BuildArray<U>,
...infer Rest
]
? true
: false;
// 맨 앞의 0을 날려줘야 함
type StringToNumber<S extends string> =
S extends `${"0"}${infer Rest extends number}`
? Rest
: S extends `${infer N extends number}`
? N
: never;
// string[]을 합쳐 string으로 변환
type Join<T extends string[]> = T extends [
infer First extends string,
...infer Rest extends string[]
]
? `${First}${Join<Rest>}`
: "";
type GreaterThan<
T extends number,
U extends number,
TupleT extends string[] = StringToTuple<`${T}`>,
TupleU extends string[] = StringToTuple<`${U}`>
> =
// 같은 값인지 비교
T extends U
? false
: // 두 숫자의 자릿수가 같은지 비교
TupleT["length"] extends TupleU["length"]
? TupleT["length"] extends 1
? // 자릿수가 모두 1일 경우, 한자리수 비교
CompareDigit<T, U>
: // 실제 앞에서부터 한글자씩 비교 로직
TupleT extends [
infer TFirst extends string,
...infer TRest extends string[]
]
? TupleU extends [
infer UFirst extends string,
...infer URest extends string[]
]
? TFirst extends UFirst
? GreaterThan<
StringToNumber<Join<TRest>>,
StringToNumber<Join<URest>>
>
: CompareDigit<StringToNumber<TFirst>, StringToNumber<UFirst>>
: true
: false
: // 자릿수가 다를 경우, length들끼리 비교
CompareDigit<TupleT["length"], TupleU["length"]>;
코드 설명
같은 값일 경우 false 리턴
이후 두 숫자의 자릿수가 같은지 비교
자릿수가 같고 한자리수일 경우, 두 숫자를 비교하여 결과 리턴
자릿수가 같고 한자리수가 아닐 경우, 재귀로 비교(앞의 한 자리씩)
자릿수가 다를 경우, 각 자릿수를 비교하여 결과 리턴
StringToTuple
함수는 문자열을 튜플로 변환
BuildArray
함수는 숫자에 따라 그 길이만큼의 unknown[] 타입을 생성
CompareDigit
함수는 두 숫자를 비교하여 결과 리턴
StringToNumber
함수는 문자열을 숫자로 변환
Join
함수는 튜플을 문자열로 변환
이 챌린지에서는 Zip<T, U>
타입을 구현해야 합니다. 여기서 T
와 U
는 반드시 Tuple
이어야 합니다.
예시
type exp = Zip<[1, 2], [true, false]>; // expected to be [[1, true], [2, false]]
문제 설명
접근 방법
코드
type Zip<T extends any[], U extends any[]> = T extends [
infer TFirst,
...infer TRest
]
? U extends [infer UFirst, ...infer URest]
? [[TFirst, UFirst], ...Zip<TRest, URest>]
: []
: [];
코드 설명
IsTuple
이라는 타입을 구현하세요. 이 타입은 입력 타입 T
를 받아서 T
가 튜플 타입인지 여부를 반환합니다.
예시
type case1 = IsTuple<[number]>; // true
type case2 = IsTuple<readonly [number]>; // true
type case3 = IsTuple<number[]>; // false
문제 설명
접근 방법
코드
type IsTuple<T> = [T] extends [never]
? false
: T extends readonly any[]
? number extends T["length"]
? false
: true
: false;
코드 설명