-
[Type-challenges] 531, 599, 612, 645, 949Front-End/TypeScript 2024. 4. 6. 06:20
🍀 목차
531 - String to Union
599 - Merge
612 - KebabCase
645 - Diff
949 - AnyOf531 - String to Union
// 문자열 인수를 입력받는 String to Union 유형을 구현하세요. // 출력은 입력 문자열의 Union type이어야 합니다. // 예시 type Test = "123" type Result = StringToUnion<Test> // expected to be "1" | "2" | "3"
/* _____________ 여기에 코드 입력 _____________ */ type StringToUnion<T extends string> = any /* _____________ 테스트 케이스 _____________ */ import type { Equal, Expect } from '@type-challenges/utils' type cases = [ Expect<Equal<StringToUnion<''>, never>>, Expect<Equal<StringToUnion<'t'>, 't'>>, Expect<Equal<StringToUnion<'hello'>, 'h' | 'e' | 'l' | 'l' | 'o'>>, Expect<Equal<StringToUnion<'coronavirus'>, 'c' | 'o' | 'r' | 'o' | 'n' | 'a' | 'v' | 'i' | 'r' | 'u' | 's'>>, ]
type StringToUnion<T extends string> = T extends `${infer First}${infer Rest}` ? First | StringToUnion<Rest> : never;
599 - Merge// 두개의 타입을 새로운 타입으로 병합하세요. // 두번째 타입의 Key가 첫번째 타입을 덮어씁니다(재정의합니다) // 예시 type foo = { name: string age: string } type coo = { age: number sex: string } type Result = Merge<foo, coo> // expected to be {name: string, age: number, sex: string}
/* _____________ 여기에 코드 입력 _____________ */ type Merge<F, S> = any /* _____________ 테스트 케이스 _____________ */ import type { Equal, Expect } from '@type-challenges/utils' type Foo = { a: number b: string } type Bar = { b: number c: boolean } type cases = [ Expect<Equal<Merge<Foo, Bar>, { a: number b: number c: boolean }>>, ]
type Merge<F, S> = { [key in keyof F | keyof S]: key extends keyof S ? S[key] : key extends keyof F ? F[key] : never; }
612 - KebabCase// camelCase나 PascalCase를 kebab-case 문자열로 수정하세요. // FooBarBaz -> foo-bar-baz // 예시 type FooBarBaz = KebabCase<"FooBarBaz"> const foobarbaz: FooBarBaz = "foo-bar-baz" type DoNothing = KebabCase<"do-nothing"> const doNothing: DoNothing = "do-nothing"
/* _____________ 여기에 코드 입력 _____________ */ type KebabCase<S> = any /* _____________ 테스트 케이스 _____________ */ import type { Equal, Expect } from '@type-challenges/utils' type cases = [ Expect<Equal<KebabCase<'FooBarBaz'>, 'foo-bar-baz'>>, Expect<Equal<KebabCase<'fooBarBaz'>, 'foo-bar-baz'>>, Expect<Equal<KebabCase<'foo-bar'>, 'foo-bar'>>, Expect<Equal<KebabCase<'foo_bar'>, 'foo_bar'>>, Expect<Equal<KebabCase<'Foo-Bar'>, 'foo--bar'>>, Expect<Equal<KebabCase<'ABC'>, 'a-b-c'>>, Expect<Equal<KebabCase<'-'>, '-'>>, Expect<Equal<KebabCase<''>, ''>>, Expect<Equal<KebabCase<'😎'>, '😎'>>, ]
type KebabCase<S extends string> = S extends `${infer First}${infer Rest}` ? Rest extends Uncapitalize<Rest> ? `${Uncapitalize<First>}${KebabCase<Rest>}` : `${Uncapitalize<First>}-${KebabCase<Rest>}` : S;
Uncapitalize<StringType>
(문서)는 전달받은 string의 첫 문자를 소문자로 변경한다.Rest extends Uncapitalize<Rest>
로 뒤에 있는 문자가 소문자로 시작한다면 기존 string 첫 문자 뒤에 바로, 그렇지 않다면 하이픈(-)을 붙인 후, 다시 Rest에 대해서 KebabCase 로직을 실행한다.
645 - Diff// O & O1의 차이점인 객체를 가져옵니다
/* _____________ 여기에 코드 입력 _____________ */ type Diff<O, O1> = any /* _____________ 테스트 케이스 _____________ */ import type { Equal, Expect } from '@type-challenges/utils' type Foo = { name: string age: string } type Bar = { name: string age: string gender: number } type Coo = { name: string gender: number } type cases = [ Expect<Equal<Diff<Foo, Bar>, { gender: number }>>, Expect<Equal<Diff<Bar, Foo>, { gender: number }>>, Expect<Equal<Diff<Foo, Coo>, { age: string, gender: number }>>, Expect<Equal<Diff<Coo, Foo>, { age: string, gender: number }>>, ]
type Foo = { name: string age: string } type Bar = { name: string age: string gender: number }
type test1 = keyof (Foo&Bar); // "name" | "age" | "gender" type test2 = keyof (Foo|Bar); // "name" | "age"
위의 결과들과
Exclude
를 사용해서keyof (Foo&Bar)
에서keyof (Foo|Bar)
을 제외시킨다.type MyExclude<T,U> = T extends U ? never : T; type test = MyExclude<keyof (Foo&Bar), keyof (Foo|Bar)> // "gender"
Omit
을 사용하여 도출된 속성을 제거한 타입을 정의하면 된다.type MyExclude<T,U> = T extends U ? never : T; type MyOmit<T,K> = { [key in MyExclude<keyof T, keyof K>] : T[key] } type Diff<O, O1> = MyOmit<O&O1, O|O1>
949 - AnyOf// Implement Python liked any function in the type system. // A type takes the Array and returns true if any element of the Array is true. // If the Array is empty, return false. // Python의 any function을 타입 시스템으로 구현하세요 // 배열을 사용하고 배열의 요소가 참이면 true를 반환합니다. 배열이 비어 있으면 false를 반환합니다 // 예시 type Sample1 = AnyOf< [1, "", false, [], {}] > // expected to be true. type Sample2 = AnyOf< [0, "", false, [], {}] > // expected to be false.
/* _____________ 여기에 코드 입력 _____________ */ type AnyOf<T extends readonly any[]> = any /* _____________ 테스트 케이스 _____________ */ import type { Equal, Expect } from '@type-challenges/utils' type cases = [ Expect<Equal<AnyOf<[1, 'test', true, [1], { name: 'test' }, { 1: 'test' }]>, true>>, Expect<Equal<AnyOf<[1, '', false, [], {}]>, true>>, Expect<Equal<AnyOf<[0, 'test', false, [], {}]>, true>>, Expect<Equal<AnyOf<[0, '', true, [], {}]>, true>>, Expect<Equal<AnyOf<[0, '', false, [1], {}]>, true>>, Expect<Equal<AnyOf<[0, '', false, [], { name: 'test' }]>, true>>, Expect<Equal<AnyOf<[0, '', false, [], { 1: 'test' }]>, true>>, Expect<Equal<AnyOf<[0, '', false, [], { name: 'test' }, { 1: 'test' }]>, true>>, Expect<Equal<AnyOf<[0, '', false, [], {}, undefined, null]>, false>>, Expect<Equal<AnyOf<[]>, false>>, ]
type AnyOf<T extends readonly any[]> = T[number] extends 0 | '' | false | [] | undefined | null ? false : true; // 통과 못함 Expect<Equal<AnyOf<[0, '', false, [], {}, undefined, null]>, false>>
통과하기 위해
{ }
를 조건에 추가한다면 key가 있는 객체도 모두 포함되게 된다.extends
는 상속 또는 확장을 나타내고, 빈 객체는 모든 객체의 상위 개념이기 때문이다 (배열은 요소의 집합이고 빈 배열 타입으로부터 확장되지 않는다).빈 객체를 표현하는 인덱스 시그니처를 추가한다.
type AnyOf<T extends readonly any[]> = T[number] extends 0 | '' | false | [] | undefined | null | {[key : string] : never} ? false : true;
참고자료