카테고리 없음
TS 타입 챌린지 스터디 - 12
LucetTin5
2025. 3. 29. 10:26
Week 12
Medium-4499-Chunk
type Chunk<
T extends readonly unknown[],
N extends number,
CurrentChunk extends readonly unknown[] = [],
Result extends readonly unknown[] = []
> = T extends []
? CurrentChunk extends []
? Result
: [...Result, CurrentChunk]
: T extends [infer F, ...infer Rest]
? CurrentChunk["length"] extends N
? Chunk<Rest, N, [F], [...Result, CurrentChunk]>
: Chunk<Rest, N, [...CurrentChunk, F], Result>
: never;
CurrentChunk
와Result
은 빈 배열로 초기화하여 chunk를 분리하는 작업을 진행할 배열과 결과를 저장할 배열로 사용한다.- 문제는
T
가 튜플이어야 함을 안내하고 있어readonly unknown[]
로 제한을 두었다. T extends []
를 통해 먼저 T가 빈 배열인지 확인한다.- 만일 빈 배열이라면 일단
CurrentChunk
가 빈 배열인지를 확인한다. CurrentChunk
도 빈 배열이라면, 빈 배열을 받았거나 모든 분리가 완료되어Result
에 저장된 경우이므로Result
을 반환한다.- 다만
T
는 비었으나,CurrentChunk
가 빈 배열이 아니라면, chunk 크기에 도달하지 못한 마지막CurrentChunk
이므로 이를 Result에 추가하여 반환한다. T
가 비어있지 않다면 앞에서부터 하나씩 떼어내고,CurrentChunk
에 넣기 위해 현재CurrentChunk
의 길이가N
과 같은지 확인한다.CurrentChunk
에 넣을 수 있는 경우는CurrentChunk
에 추가하고 다음 요소로 넘어간다.CurrentChunk
에 넣을 수 없는,CurrentChunk
가 지정된 청크 사이즈가 된 경우, 이를Result
에 추가하고CurrentChunk
는 새로운 인자를 담아 초기화하고 이를 반복한다.- 마지막
never
는 도달할 수 없는 조건절임을 명시했다.
Medium-4518-Fill
type Fill<
T extends readonly unknown[],
N,
Start extends number = 0,
End extends number = T["length"],
IsStart extends boolean = false,
Result extends readonly unknown[] = []
> = T extends [infer F, ...infer Rest]
? Start extends End
? [...Result, ...T]
: IsStart extends false
? Result["length"] extends Start
? Fill<Rest, N, Start, End, true, [...Result, N]>
: Fill<Rest, N, Start, End, false, [...Result, F]>
: Result["length"] extends End
? [...Result, ...T]
: Fill<Rest, N, Start, End, true, [...Result, N]>
: Result;
IsStart
플래그를 추가하여Start
에서 교체가 시작되었는지 확인한다.Result
는 빈 배열로 초기화하여 결과값을 담을 배열로 사용한다.T
가 완전히 빈 배열이 된다면Result
를 반환한다. (마지막 줄, 탈출 조건)- 먼저
T
를 첫 요소와 나머지로 나눈다.Start
와End
가 동일한 수인 경우 교체가 일어나지 않으므로 그대로 반환한다. IsStart
가 false이면서,Result["length"]
가 Start와 같아진 경우F
대신N
을 넣고 재귀를 진행한다.IsStart
가 true이면서,Result["length"]
가 End와 같아진 경우는 모든 교체가 끝난 것이므로Result
를 반환하되,T
에 남은 요소가 있을 수 있으므로 이를 함께 반환한다.IsStart
가 true이면서,Result["length"]
가 End와 같지 않다면 계속 교체를 진행한다.
Medium-4803-TrimRight
type Space = " " | "\n" | "\t";
type TrimRight<S extends string> = S extends `${infer Rest}${Space}`
? TrimRight<Rest>
: S;
- TrimLeft 문제와 유사하다.
- 동일하게
Space
타입을 정의하고, 이번엔 문자열의 뒤에서Space
템플릿 리터럴 매칭을 통해 재귀를 진행하여Space
가 없을 때까지 반복한다.
Medium-5117-Without
type CreateUnion<
T extends number | unknown[],
Union extends any[] = []
> = T extends number
? T
: T extends [infer F, ...infer Rest]
? CreateUnion<Rest, [...Union, F]>
: Union[number];
type Without<
T extends readonly any[],
U extends number | any[],
Union extends any[] = CreateUnion<U>
> = T extends [infer F, ...infer Rest]
? F extends Union
? Without<Rest, U, Union>
: [F, ...Without<Rest, U, Union>]
: T;
lodash
의without
함수는 Array에서 특정 요소들을 제거하는 함수이다.CreateUnion
타입은U
의 요소들을 Union 타입으로 변환한다.Without
의T
는 배열로 주어지기에[infer F, ...infer Rest]
로 나누어 재귀를 진행한다.F
가Union
에 속하는지 확인하고 속한다면 제외한 나머지 배열에 대해 진행하고, 속하지 않는다면 결과에 포함시킨다.- 마지막으로
T
가 빈 배열이 되면 모든 재귀가 끝난 것이므로 결과를 반환한다.
Medium-5140-Trunc
type Trunc<T extends string | number> =
`${T}` extends `${infer Integer}.${infer _}`
? Integer extends ""
? "0"
: Integer extends `-`
? "-0"
: Integer
: `${T}`;
Math.trunc
함수는 소수점 이하를 버리는 함수이다.- 문자열로 변환하여 템플릿 리터럴 매칭을 진행하고 정수부를 떼어낸다.
- 이 때, 빈 문자열이 된다면
0
을 (소수부만 존재하는.xxx
형태) 반환하고, - 부호만 남는 (-.xxx
) 형태는-0
을 반환한다. - 나머지 정수부가 분리된 경우는 그대로 반환한다.
Medium-5153-IndexOf
type Same<A, B> = (<T>() => T extends A ? 1 : 2) extends <T>() => T extends B
? 1
: 2
? true
: false;
type IndexOf<
T extends readonly unknown[],
U,
Count extends any[] = []
> = T extends [infer F, ...infer Rest]
? Same<F, U> extends true
? Count["length"]
: IndexOf<Rest, U, [...Count, 0]>
: -1;
Same
타입은 두 타입이 동일한지를 확인한다. 이 때, 타입을 나타내는 문자열 자체가 동일한지를 확인하기 위해 함수 형태를 사용한다. (Equal
타입이 이렇게 구현되어 있다.)Same
타입을 활용하는 이유는number
타입이 튜플에 들어있고 이를 찾아내고자 할 때F extends number
가 아니라Same<F, number>
를 이용하여"number"
라고 쓰여지는 그 자체를 찾아야 하기 때문이다.- 1, 2 등도
F extends number
에서true
가 되어 정확하게 찾고자 하는 값을 찾을 수 없다. - 다른 예시로는
any
를 찾고자 할 때F extends any
는 어떤 경우에도 성립하기 때문에 함수에 기반한 형태로 찾아야 한다. Count
는 빈 배열로 초기화하고 재귀를 진행하며 크기를 키워 현재의 인덱스를 카운트한다.