[TS] Type-Challenges 스터디 12주차
![[TS] Type-Challenges 스터디 12주차](/_next/image?url=https%3A%2F%2Fvelog.velcdn.com%2Fimages%2Fhayou%2Fpost%2F83ae96d6-0d7d-4f60-9aac-cedad8b0f405%2Fimage.jpg&w=3840&q=75)
[medium] 4499. Chunk
문제
주어진 배열을 특정 길이의 청크로 나누는 문제입니다.
lodash를 아시나요? Chunk는 lodash에서 매우 유용한 함수입니다. 이제 이것을 구현해보겠습니다.
Chunk<T, N>는 두 개의 필수 타입 매개변수를 받습니다. T는 반드시 튜플이어야 하고, N은 반드시 1 이상의 정수여야 합니다.
예시
type exp1 = Chunk<[1, 2, 3], 2>; // 예상 결과: [[1, 2], [3]]
type exp2 = Chunk<[1, 2, 3], 4>; // 예상 결과: [[1, 2, 3]]
type exp3 = Chunk<[1, 2, 3], 1>; // 예상 결과: [[1], [2], [3]]
문제 설명
- 이 문제는 주어진 배열을 특정 길이의 청크(배열)로 나누는 타입을 구현
- 주어진 배열이 튜플인지 확인하고, 청크의 길이(N)가 1 이상인지 확인
- 청크의 길이가 배열의 길이보다 클 경우, 배열 자체를 반환
시도 1 (정답)
접근 방법
- 두 개의 배열을 만들어서, 하나는 청크를 만들고 하나는 청크를 채워나가는 방식
- 청크를 채워나가는 배열의 길이가 N과 같아지면, 청크를 만들어주는 배열에 추가
- 이후 재귀로 나머지 요소들에 대해서도 같은 작업을 반복
코드
type Chunk<
T extends any[],
N extends Number,
Result extends any[] = [],
Chunk extends any[] = []
> = T extends [infer First, ...infer Rest]
? Chunk["length"] extends N
? Chunk<Rest, N, [...Result, Chunk], [First]>
: Chunk<Rest, N, Result, [...Chunk, First]>
: Chunk["length"] extends 0
? Result
: [...Result, Chunk];
코드 설명
Result는 최종적으로 반환될 배열(Chunk[])Chunk는 청크를 채워나가는 배열T를 재귀적으로 탐색하면서,Chunk에 채워넣기Chunk의 길이가N과 같아지면,Result에 추가- 이후 재귀로 나머지 요소들에 대해서도 같은 작업을 반복
[medium] 4518. Fill
문제
Fill은 JavaScript의 일반적인 함수입니다. 이제 타입으로 이를 구현해보겠습니다.
Fill<T, N, Start?, End?>에서 볼 수 있듯이, Fill은 네 가지 타입의 매개변수를 받습니다. 이 중 T와 N은 필수 매개변수이고, Start와 End는 선택적 매개변수입니다.
이러한 매개변수들의 요구사항은 다음과 같습니다: T는 반드시 tuple이어야 하고, N은 어떤 타입의 값이든 될 수 있으며, Start와 End는 0보다 크거나 같은 정수여야 합니다.
예시
type exp = Fill<[1, 2, 3], 0>; // 예상 결과: [0, 0, 0]
문제 설명
- 이 문제는
Fill함수를 타입으로 구현 Fill함수는 배열T와 값N을 받아서, 배열의 일부를N으로 채우는 함수Start와End는 선택적 매개변수로, 채우기를 시작할 인덱스와 끝날 인덱스를 지정
시도 1 (정답)
접근 방법
- 배열을 재귀적으로 탐색하면서, 특정 인덱스 범위에 있는 요소들을
N으로 채우기 Start와End를 지정하지 않으면, 배열의 처음부터 끝까지 채우기- 채워야되는 index인지 확인하기 위해
Index배열을 만들어서 체크 Index배열의 길이가Start와 같아지면,Switch를true로 변경Index배열의 길이가End와 같아지면,Switch를false로 변경End도달하기 전에T가 끝나면Result반환
코드
type Fill<
T extends unknown[],
N,
Start extends number = 0,
End extends number = T["length"],
Index extends unknown[] = [],
Switch extends boolean = false,
Result extends any[] = []
> = T extends [infer First, ...infer Rest]
? Switch extends true
? // Switch가 true인 경우(Index가 End보다 클 경우)
Index["length"] extends End
? // 끝났으면 남은 배열 추가(Index가 End와 같아지면 끝나는 것이므로)
[...Result, ...T]
: // 아직 끝나지 않았으면 다음 요소 추가
Fill<Rest, N, Start, End, [...Index, unknown], Switch, [...Result, N]>
: // Switch가 false인 경우(Index가 Start보다 작을 경우)
Index["length"] extends Start
? // Switch가 false인데 Start와 같아졌을 경우
Start extends End
? // Start와 End가 같으면 N으로 변경 X(원래 값 추가)
[...Result, First, ...Rest]
: // Start와 End가 같지 않으면 N으로 변경, Switch를 true로 변경
Fill<Rest, N, Start, End, [...Index, unknown], true, [...Result, N]>
: // Switch가 false인데 Start보다 작지 않을 경우 그냥 진행
Fill<Rest, N, Start, End, [...Index, unknown], Switch, [...Result, First]>
: Result;
코드 설명
T를 재귀적으로 탐색하면서First요소 확인Switch가true인 경우,Index배열의 길이가End와 같아지면 끝나는 것이므로 남은 배열 추가- 아직 끝나지 않았으면 다음 요소 추가
Switch가false인 경우,Index배열의 길이가Start와 같아지면 채워야되는 요소가 되므로N으로 변경,Switch를true로 변경- 아직 채워야되는 요소가 아니면 그냥 진행
End도달하기 전에T가 끝나면Result반환
[medium] 4803. Trim Right
문제
문자열 타입을 받아 끝부분의 공백을 제거한 새로운 문자열을 반환하는 TrimRight<T>를 구현하세요.
예시
type Trimed = TrimRight<" Hello World ">; // expected to be ' Hello World'
문제 설명
- 문자열 타입을 받아 끝부분의 공백을 제거한 새로운 문자열을 반환
시도 1 (정답)
접근 방법
- 템플릿 리터럴로 마지막 글자에 whitespaces가 들어가는 지 확인 후 들어가면 재귀
코드
type TrimRight<S extends string> = S extends `${infer T}${" " | "\n" | "\t"}`
? TrimRight<T>
: S;
코드 설명
S를 재귀적으로 탐색하면서T요소 확인T요소가whitespaces(' ' | '\n' | '\t')가 들어가는 지 확인whitespaces가 들어가면 재귀whitespaces가 들어가지 않으면 그냥 반환
[medium] 5117. Without
문제
Lodash의 without 함수를 타입 버전으로 구현하세요. Without<T, U>는 배열 T와 숫자 또는 배열 U를 받아서 U의 요소들을 제외한 배열을 반환합니다.
예시
type Res = Without<[1, 2], 1>; // expected to be [2]
type Res1 = Without<[1, 2, 4, 1, 5], [1, 2]>; // expected to be [4, 5]
type Res2 = Without<[2, 3, 2, 3, 2, 3, 2, 3], [2, 3]>; // expected to be []
문제 설명
- 배열
T와 숫자 또는 배열U를 받아서U의 요소들을 제외한 배열을 반환 U는 숫자 또는 배열이 들어올 수 있음
시도 1 (정답)
접근 방법
- 배열
T를 재귀적으로 탐색하면서U의 요소들을 제외한 배열을 반환
코드
type TupleToUnion<T extends readonly number[] | number> = T extends number[]
? T[number]
: T;
type Without<T extends any[], U extends number | number[]> = T extends [
infer First,
...infer Rest
]
? First extends TupleToUnion<U>
? [...Without<Rest, U>]
: [First, ...Without<Rest, U>]
: T;
코드 설명
TupleToUnion<U>는U가 튜플일 경우 유니온 타입으로 변환Without<T, U>는 배열T를 재귀적으로 탐색하면서U의 요소들을 제외한 배열을 반환
[medium] 5140. Trunc
문제
문자열이나 숫자를 받아서 소수점 이하 자릿수를 제거하여 정수 부분만 반환하는 Math.trunc의 타입 버전을 구현하세요.
예시:
type A = Trunc<12.34>; // 12
시도 1
접근 방법
number일 경우string으로 변환- 변환된 문자열에서 소수점 이하 자릿수를 제거하여 정수 부분만 반환
코드
type Trunc<
T extends number | string,
S = `${T}`
> = S extends `${infer First}.${infer _}` ? `${First}` : S;
실패 원인
.3,-.3등의 예외 케이스 처리 실패
시도 2 (정답)
접근 방법
- 만약
infer로 추론한First가 빈 문자열이거나-일 경우 0으로 처리 - 그 외에는 그대로 반환
코드
type Trunc<
T extends number | string,
S = `${T}`
> = S extends `${infer First}.${infer _}`
? First extends "" | "-"
? `${First}0`
: First
: S;
코드 설명
S는T를 문자열로 변환한 결과S가.를 포함할 경우,First가 빈 문자열이거나-일 경우First+0으로 처리- 아닐 경우
First를 그대로 반환 S가.를 포함하지 않을 경우,S를 그대로 반환
[medium] 5153. IndexOf
문제
배열의 Array.indexOf 메서드의 타입 버전을 구현하세요. indexOf<T, U>는 배열 T와 임의의 값 U를 받아서 배열 T에서 처음 등장하는 U의 인덱스를 반환합니다.
type Res = IndexOf<[1, 2, 3], 2>; // expected to be 1
type Res1 = IndexOf<[2, 6, 3, 8, 4, 1, 7, 3, 9], 3>; // expected to be 2
type Res2 = IndexOf<[0, 0, 0], 2>; // expected to be -1
시도 1
접근 방법
index를 계산하는 어레이를 하나 둬서length로 어레이 값 리턴- 튜플을
infer로 하나씩 확인하며index Array에 요소 하나씩 증가
코드
type IndexOf<T extends any[], U, IndexArr extends unknown[] = []> = T extends [
infer First,
...infer Rest
]
? First extends U
? IndexArr["length"]
: IndexOf<Rest, U, [...IndexArr, unknown]>
: -1;
실패 원인
number와 같은 타입, 그리고any를 제대로 처리하지 못함FirstextendsU대신 더 강력한 타입비교를 만들어야 할 듯
시도 2 (정답)
접근 방법
- 기존에 사용한
MyEqual타입을 가져와서First extends U대신 사용
코드
type MyEqual<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y
? 1
: 2
? true
: false;
type IndexOf<T extends any[], U, IndexArr extends unknown[] = []> = T extends [
infer First,
...infer Rest
]
? MyEqual<First, U> extends true
? IndexArr["length"]
: IndexOf<Rest, U, [...IndexArr, unknown]>
: -1;
참고
comments
loading…