[TS] Type-Challenges 스터디 5주차
![[TS] Type-Challenges 스터디 5주차](/_next/image?url=https%3A%2F%2Fvelog.velcdn.com%2Fimages%2Fhayou%2Fpost%2F6163f813-0d4d-43af-b9d2-f948831bbee1%2Fimage.jpg&w=3840&q=75)
[Medium] 110. Capitalize
View on GitHub: https://tsch.js.org/110
문제
문자열의 첫 글자만 대문자로 바꾸고 나머지는 그대로 놔두는 Capitalize<T>를 구현하세요.
정답
type MyCapitalize<S extends string> = S extends `${infer First}${infer Rest}`
? `${Uppercase<First>}${Rest}`
: "";
시도했던 오답
// 1차 시도
type MyCapitalize<S extends string> = S extends `${infer First}${infer Rest}`
? `${First["toUpperCase"]}${Rest}`
: "";
설명
infer키워드를 사용하여 문자열을 첫 글자와 나머지 문자열로 분리- 첫 글자를
Uppercase타입으로 변환 (S["toUpperCase"]가 될 줄 알았음...) - 나머지 문자열을 첫 글자와 합쳐서 반환
Reference
[Medium] 116. Replace
View on GitHub: https://tsch.js.org/116
문제
문자열 S에서 From를 찾아 한 번만 To로 교체하는 Replace<S, From, To>를 구현하세요.
정답
type Replace<
S extends string,
From extends string,
To extends string,
> = From extends ""
? S
: S extends `${infer RestHead}${From}${infer RestTail}`
? `${RestHead}${To}${RestTail}`
: S;
시도했던 오답
// 1차 시도
type Replace<
S extends string,
From extends string,
To extends string,
> = S extends `${infer RestHead}${From}${infer RestTail}`
? `${RestHead}${To}${RestTail}`
: S;
설명
From이 빈 문자열인 경우 원래 문자열을 반환infer키워드를 사용하여 문자열을RestHead,From,RestTail로 분리S가From을 포함하는 경우(조건이 True 일 때)From을To로 교체하고 나머지 문자열을 합쳐서 반환From이 빈 문자열이 아니고S가From을 포함하지 않는 경우 원래 문자열을 반환
[Medium] 116. ReplaceAll
View on GitHub: https://tsch.js.org/119
문제
문자열 S에서 From를 찾아 모두 To로 교체하는 ReplaceAll<S, From, To>를 구현하세요.
정답
type ReplaceAll<
S extends string,
From extends string,
To extends string,
> = From extends ""
? S
: S extends `${infer RestHead}${From}${infer RestTail}`
? `${RestHead}${To}${ReplaceAll<RestTail, From, To>}`
: S;
시도했던 오답
// 1차 시도
type ReplaceAll<
S extends string,
From extends string,
To extends string,
> = S extends `${infer RestHead}${From}${infer RestTail}`
? ReplaceAll<`${RestHead}${To}${RestTail}`, From, To>
: S;
설명
From이 빈 문자열인 경우 원래 문자열을 반환infer키워드를 사용하여 문자열을RestHead,From,RestTail로 분리S가From을 포함하는 경우(조건이 True 일 때)From을To로 교체하고From이후 문자열(RestTail)을 재귀적으로 처리From이 빈 문자열이 아니고S가From을 포함하지 않는 경우 원래 문자열을 반환
[Medium] 191. Append Argument
View on GitHub: https://tsch.js.org/191
문제
함수 타입 Fn과 어떤 타입 A가 주어질 때 Fn의 인수와 A를 마지막 인수로 받는 Fn과 동일한 함수 유형인 G를 생성하세요.
정답
type AppendArgument<Fn extends (...args: any[]) => any, A> = Fn extends (
...args: infer Args
) => infer Return
? (...args: [...Args, A]) => Return
: never;
시도했던 오답
// 1차 시도
type AppendArgument<Fn extends (...args: any[]) => any, A> = Fn extends (
...args: infer Args
) => infer Return
? ([Args, A]) => Return
: never;
설명
- 우선
Fn에서 인수와 반환 타입을 추출해야 됨 [easy] 3312-parameters문제를 참고하여 인수를 추출[medium] 2-return-type문제를 참고하여 반환 타입을 추출- 추출된 인수에 A를 추가하여 반환 타입을 반환하는 함수 타입을 생성
- 이 때 추출된 인수는 배열로 추출되므로 스프레드 배열에 A를 추가
Reference
- [easy] 3312-parameters
- [medium] 2-return-type
[Medium] 296. Permutation
View on GitHub: https://tsch.js.org/296
문제
주어진 유니언 타입을 순열 배열로 바꾸는 Permutation 타입을 구현하세요.
정답
type Permutation<T, K = T> = [T] extends [never]
? []
: K extends K
? [K, ...Permutation<Exclude<T, K>>]
: never;
설명
-
<T, K = T>:T를 기본값으로 설정하는 변수K생성K extends K에서 유니온 분배를 위해 사용
-
[T] extends [never]:T가never인 경우를 체크T가never인 경우, 빈 배열을 반환해서 순열 생산 종료 (재귀 종료)T extends never를 사용하지 않는 이유는 분배법칙을 막기 위해서
-
K extends K:T와 동일한K를 유니온 분배하여 순회K(유니온)를 순회하며 각 요소에 대해 재귀 호출
-
[K, ...Permutation<Exclude<T, K>>]:K를 제외한T의 순열을 구하는 재귀 호출K extends K에서 분배된 요소를 순회하며 재귀 호출Exclude<T, K>:T에서K를 제외한 타입으로 재귀 호출
type Test = Permutation<"A" | "B" | "C">;
// 1단계: K = 'A'
// 결과: ['A', ...Permutation<'B' | 'C'>]
// 2단계: K = 'B'
// 결과: ['B', ...Permutation<'A' | 'C'>]
// 3단계: K = 'C'
// 결과: ['C', ...Permutation<'A' | 'B'>]
추가 질문
K extends K제대로 이해하기
K extends K는 항상 참이므로, 결국 모든 유니온 분배를 트리거하는 역할
type Test<K> = K extends K ? [K] : never;
type Result = Test<"A" | "B" | "C">;
- 이 예시의 경우 다음과 같이 동작함
'A' extends 'A' ? ['A'] : never → ['A']
'B' extends 'B' ? ['B'] : never → ['B']
'C' extends 'C' ? ['C'] : never → ['C']
-
그리고 해당 결과를 유니온으로 합쳐
['A'] | ['B'] | ['C']반환 -
만약 분배법칙을 적용하지 않으려면
K를 배열로 감싸서[K]로 표현해야 함
type NoDistribute<K> = [K] extends [K] ? [K] : never;
type Result = NoDistribute<"A" | "B" | "C">;
// Result는 ['A' | 'B' | 'C']
Reference
[Medium] 298. Length Of String
View on GitHub: https://tsch.js.org/298
문제
String#length처럼 동작하는 문자열 리터럴의 길이를 구하세요.
정답
type StringToTuple<S extends String> = S extends `${infer First}${infer Last}`
? [First, ...StringToTuple<Last>]
: [];
type LengthOfString<S extends string> = StringToTuple<S>["length"];
설명
StringToTuple함수는 문자열을 튜플로 변환하는 함수String타입이 인자로 들어오면 한 글자씩 나눠 튜플로 변환- 그렇게 구해진 튜플의 길이를 반환하면 문자열의 길이를 구할 수 있음
comments
loading…