본문 바로가기
Language/Typescript

타입챌린지 : 612-KebabCase (medium)

by hsloth 2023. 4. 16.

 

이 글은 제가 타입챌린지를 하면서 해석한 내용을 적는 글입니다. 틀린 내용이 있으면 댓글 달아주시면 감사하겠습니다.

 

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

 

GitHub - type-challenges/type-challenges: Collection of TypeScript type challenges with online judge

Collection of TypeScript type challenges with online judge - GitHub - type-challenges/type-challenges: Collection of TypeScript type challenges with online judge

github.com

 

제네릭으로 문자열을 받으면 해당 문자열을 케밥 케이스로 바꾸는 타입이다.

케밥 케이스란 문자열이 소문자와 -(하이픈)으로 이루어진 형태를 말한다.

 

참고하면 좋은 포스팅

https://suloth.tistory.com/61

 

타입챌린지 : 110-Capitalize (medium)

이 글은 제가 타입챌린지를 하면서 해석한 내용을 적는 글입니다. 틀린 내용이 있으면 댓글 달아주시면 감사하겠습니다. https://github.com/type-challenges/type-challenges/blob/main/questions/00110-medium-capitalize/

suloth.tistory.com

 

위의 포스팅...에서도 조금 어거지로 풀었는데... 이번 포스팅에서도 조금 억지로 풀었다 ㅋㅋㅋ

 

type Lower = {
  A: 'a', B: 'b', C: 'c', D: 'd', E: 'e', F: 'f', G: 'g', H: 'h', I: 'i',
  J: 'j', K: 'k', L: 'l', M: 'm', N: 'n', O: 'o', P: 'p', Q: 'q', R: 'r',
  S: 's', T: 't', U: 'u', V: 'v', W: 'w', X: 'x', Y: 'y', Z: 'z'
}


type KebabCase<S extends string, U extends string = S> = S extends `${infer F}${infer O}` ?
  F extends keyof Lower ?
  U extends S ?
  `${Lower[F]}${KebabCase<O, S>}` : `-${Lower[F]}${KebabCase<O, S>}` :
  `${F}${KebabCase<O, S>}` : '';


/* _____________ Test Cases _____________ */
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<'😎'>, '😎'>>,
]

Lower라는 타입을 정해놓고, 대문자가 들어가면 소문자를 뱉을 수 있도록 정의하였다.

type KebabCase<S extends string, U extends string = S> : KebabCase라는 타입을 정의하는데, S는 문자열이고, U도 문자열인데 디폴트값으로 S를 갖는다. U를 추가한 이유는 첫문자가 대문자인 경우 (-)하이픈을 붙이지 않게 하려고 넣어주었다.

S extends `${infer F}${infer O}` ? F extends keyof Lower ? : S가 첫 문자F와 나머지 문자열로 나뉠 때, F가 Lower의 key중 하나라면,

U extends S ? `${Lower[F]}${KebabCase<O, S>}` : `-${Lower[F]}${KebabCase<O, S>}` : U가 S와 동일하다면(KebabCase를 재귀로 호출할 건데, 이 때, U와 S를 첫 문자에 대해 판단할 때만 같게주고 나머지는 다르게 주어 첫 문자에는 -가 안붙도록 하기 위함) -를 안붙이고, U가 S와 다르다면 -를 붙인다. 이 때, F를 소문자로 바꾸고 뒤에 나머지 문자열 O를 KebabCase로 재귀로 호출한다. 그리고 KebabCase<O, S> 처럼 S를 넣어준다(문자열 비교를 위함)

`${F}${KebabCase<O, S>}` : ''; : 그리고 만약 F가 Lower의 key가 아닌 경우, F를 그대로 반환하고, 그것도 아니라면 빈 문자열을 반환한다.

 

 


다른 분들의 정답을 봤는데... Uncapitalize라는 타입이 있더라... 이걸 사용하면 훨씬 쉽게 풀 수 있다.