-
[Type-challenges] 108, 110, 116, 119, 191Front-End/TypeScript 2024. 3. 15. 14:12
🍀 목차
108 - Trim
110 - Capitalize
116 - Replace
119 - ReplaceAll
191 - Append Argument108 - 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;
참고자료