🌱 ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Type-challenges] 531, 599, 612, 645, 949
    Front-End/TypeScript 2024. 4. 6. 06:20
    🍀 목차
    531 - String to Union
    599 - Merge
    612 - KebabCase
    645 - Diff
    949 - AnyOf

     

    531 - 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;

     

     

    참고자료

    https://github.com/type-challenges/type-challenges/blob/main/questions/00531-medium-string-to-union/README.ko.md

    https://github.com/type-challenges/type-challenges/blob/main/questions/00599-medium-merge/README.ko.md

    https://github.com/type-challenges/type-challenges/blob/main/questions/00612-medium-kebabcase/README.ko.md

    https://github.com/type-challenges/type-challenges/blob/main/questions/00645-medium-diff/README.ko.md

    https://github.com/type-challenges/type-challenges/blob/main/questions/00949-medium-anyof/README.ko.md

    댓글

🍀 Y0ungZ dev blog.
스크롤 버튼