Front-End/TypeScript
[Type-challenges] 108, 110, 116, 119, 191
Y0ungZ
2024. 3. 15. 14:12
🍀 목차
108 - Trim
110 - Capitalize
116 - Replace
119 - ReplaceAll
191 - Append Argument
108 - Trim
// 정확한 문자열 타입이고 양쪽 끝의 공백이 제거된 새 문자열을 반환하는 Trim<T>를 구현하십시오.
// 예시
type trimmed = Trim<' Hello World '> // 기대되는 결과는 'Hello World'입니다.
/* _____________ 여기에 코드 입력 _____________ */
type Trim<S extends string> = any
/* _____________ 테스트 케이스 _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<Trim<'str'>, 'str'>>,
Expect<Equal<Trim<' str'>, 'str'>>,
Expect<Equal<Trim<' str'>, 'str'>>,
Expect<Equal<Trim<'str '>, 'str'>>,
Expect<Equal<Trim<' str '>, 'str'>>,
Expect<Equal<Trim<' \n\t foo bar \t'>, 'foo bar'>>,
Expect<Equal<Trim<''>, ''>>,
Expect<Equal<Trim<' \n\t '>, ''>>,
]
type Space = ' ' | '\t' | '\n';
type Trim<S extends string> = S extends `${Space}${infer T}` | `${infer T}${Space}` ? Trim<T> : S;
110 - Capitalize
// 문자열의 첫 글자만 대문자로 바꾸고 나머지는 그대로 놔두는 Capitalize<T>를 구현하세요.
// 예시
type capitalized = Capitalize<'hello world'> // expected to be 'Hello world'
/* _____________ 여기에 코드 입력 _____________ */
type MyCapitalize<S extends string> = any
/* _____________ 테스트 케이스 _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<MyCapitalize<'foobar'>, 'Foobar'>>,
Expect<Equal<MyCapitalize<'FOOBAR'>, 'FOOBAR'>>,
Expect<Equal<MyCapitalize<'foo bar'>, 'Foo bar'>>,
Expect<Equal<MyCapitalize<''>, ''>>,
Expect<Equal<MyCapitalize<'a'>, 'A'>>,
Expect<Equal<MyCapitalize<'b'>, 'B'>>,
Expect<Equal<MyCapitalize<'c'>, 'C'>>,
Expect<Equal<MyCapitalize<'d'>, 'D'>>,
Expect<Equal<MyCapitalize<'e'>, 'E'>>,
Expect<Equal<MyCapitalize<'f'>, 'F'>>,
Expect<Equal<MyCapitalize<'g'>, 'G'>>,
Expect<Equal<MyCapitalize<'h'>, 'H'>>,
Expect<Equal<MyCapitalize<'i'>, 'I'>>,
Expect<Equal<MyCapitalize<'j'>, 'J'>>,
Expect<Equal<MyCapitalize<'k'>, 'K'>>,
Expect<Equal<MyCapitalize<'l'>, 'L'>>,
Expect<Equal<MyCapitalize<'m'>, 'M'>>,
Expect<Equal<MyCapitalize<'n'>, 'N'>>,
Expect<Equal<MyCapitalize<'o'>, 'O'>>,
Expect<Equal<MyCapitalize<'p'>, 'P'>>,
Expect<Equal<MyCapitalize<'q'>, 'Q'>>,
Expect<Equal<MyCapitalize<'r'>, 'R'>>,
Expect<Equal<MyCapitalize<'s'>, 'S'>>,
Expect<Equal<MyCapitalize<'t'>, 'T'>>,
Expect<Equal<MyCapitalize<'u'>, 'U'>>,
Expect<Equal<MyCapitalize<'v'>, 'V'>>,
Expect<Equal<MyCapitalize<'w'>, 'W'>>,
Expect<Equal<MyCapitalize<'x'>, 'X'>>,
Expect<Equal<MyCapitalize<'y'>, 'Y'>>,
Expect<Equal<MyCapitalize<'z'>, 'Z'>>,
]
type MyCapitalize<S extends string> = S extends `${infer head}${infer tail}` ? `${Uppercase<head>}${tail}` : S;
Template Literal Types로 Uppercase<StrintType>을 제공한다. 빌트인 타입을 사용하지 않으려면 객체로 대문자(key)를 소문자(value)로 매치시킬 수도 있다.
116 - Replace
// 문자열 S에서 From를 찾아 한 번만 To로 교체하는 Replace<S, From, To>를 구현하세요.
// 예시
type replaced = Replace<'types are fun!', 'fun', 'awesome'>
// expected to be 'types are awesome!'
/* _____________ 여기에 코드 입력 _____________ */
type Replace<S extends string, From extends string, To extends string> = any
/* _____________ 테스트 케이스 _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<Replace<'foobar', 'bar', 'foo'>, 'foofoo'>>,
Expect<Equal<Replace<'foobarbar', 'bar', 'foo'>, 'foofoobar'>>,
Expect<Equal<Replace<'foobarbar', '', 'foo'>, 'foobarbar'>>,
Expect<Equal<Replace<'foobarbar', 'bar', ''>, 'foobar'>>,
Expect<Equal<Replace<'foobarbar', 'bra', 'foo'>, 'foobarbar'>>,
Expect<Equal<Replace<'', '', ''>, ''>>,
]
type Replace<S extends string, From extends string, To extends string> = S extends `${infer Left}${From}${infer Right}` ? `${Left}${To}${Right}` : S;
From이 공백일 때를 처리해주지 않으면 Replace<'foobarbar', '', 'foo'>의 결과가 'foobarbar'가 아닌 'ffoooobarbar'가 된다.
From이 공백일 때는 never이 반환되게 해준다.
type Replace<S extends string, From extends string, To extends string> = S extends `${infer Left}${From extends '' ? never: From}${infer Right}` ? `${Left}${To}${Right}` : S;
119 - ReplaceAll
// 주어진 문자열 S에서 부분 문자열 From을 찾아 모두 To로 교체하는 \
// 제네릭 ReplaceAll<S, From, To>을 구현하세요.
// 예시
type replaced = ReplaceAll<'t y p e s', ' ', ''> // expected to be 'types'
/* _____________ 여기에 코드 입력 _____________ */
type ReplaceAll<S extends string, From extends string, To extends string> = any
/* _____________ 테스트 케이스 _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<ReplaceAll<'foobar', 'bar', 'foo'>, 'foofoo'>>,
Expect<Equal<ReplaceAll<'foobar', 'bag', 'foo'>, 'foobar'>>,
Expect<Equal<ReplaceAll<'foobarbar', 'bar', 'foo'>, 'foofoofoo'>>,
Expect<Equal<ReplaceAll<'t y p e s', ' ', ''>, 'types'>>,
Expect<Equal<ReplaceAll<'foobarbar', '', 'foo'>, 'foobarbar'>>,
Expect<Equal<ReplaceAll<'barfoo', 'bar', 'foo'>, 'foofoo'>>,
Expect<Equal<ReplaceAll<'foobarfoobar', 'ob', 'b'>, 'fobarfobar'>>,
Expect<Equal<ReplaceAll<'foboorfoboar', 'bo', 'b'>, 'foborfobar'>>,
Expect<Equal<ReplaceAll<'', '', ''>, ''>>,
]
type ReplaceAll<S extends string, From extends string, To extends string> =
From extends '' ?
S : S extends `${infer Left}${From}${infer Right}` ?
`${ReplaceAll<Left, From, To>}${To}${ReplaceAll<Right,From,To>}` : S;
191 - Append Argument
// 함수 타입 Fn과 어떤 타입 A가 주어질 때
// Fn의 인수와 A를 마지막 인수로 받는 Fn과 동일한 함수 유형인 G를 생성하세요.
// 예시
type Fn = (a: number, b: string) => number
type Result = AppendArgument<Fn, boolean>
// 기대되는 결과는 (a: number, b: string, x: boolean) => number 입니다.
/* _____________ 여기에 코드 입력 _____________ */
type AppendArgument<Fn, A> = any
/* _____________ 테스트 케이스 _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type Case1 = AppendArgument<(a: number, b: string) => number, boolean>
type Result1 = (a: number, b: string, x: boolean) => number
type Case2 = AppendArgument<() => void, undefined>
type Result2 = (x: undefined) => void
type cases = [
Expect<Equal<Case1, Result1>>,
Expect<Equal<Case2, Result2>>,
// @ts-expect-error
AppendArgument<unknown, undefined>,
]
먼저, 삼항 연산자를 사용해 Fn이 함수 타입이 아니라면 never을 반환해 보자.
type AppendArgument<Fn extends Function, A> = Fn extends (...args: infer Args) => infer T? T : never;
반환해야 할 것은 함수의 반환값 타입만이 아닌 Fn의 매개변수에 A를 더한 새로운 함수므로 T를 아래와 같이 수정한다.
(...args : [...Args, A]) => T
기존 argument에 A를 추가하고, Fn의 반환값인 T를 그대로 반환한다.
최종적으로 정답은 아래와 같다.
type AppendArgument<Fn extends Function, A> = Fn extends (...args : infer Args) => infer T ? (...args : [...Args, A]) => T : never;