이 글은 제가 타입챌린지를 하면서 해석한 내용을 적는 글입니다. 틀린 내용이 있으면 댓글 달아주시면 감사하겠습니다.
제네릭으로 문자열을 받으면 해당 문자열을 케밥 케이스로 바꾸는 타입이다.
케밥 케이스란 문자열이 소문자와 -(하이픈)으로 이루어진 형태를 말한다.
참고하면 좋은 포스팅
위의 포스팅...에서도 조금 어거지로 풀었는데... 이번 포스팅에서도 조금 억지로 풀었다 ㅋㅋㅋ
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라는 타입이 있더라... 이걸 사용하면 훨씬 쉽게 풀 수 있다.
'Language > Typescript' 카테고리의 다른 글
타입챌린지 : 949-AnyOf (medium) (0) | 2023.04.18 |
---|---|
타입챌린지 : 645-Diff (medium) (0) | 2023.04.17 |
타입챌린지 : 599-Merge (medium) (2) | 2023.04.15 |
타입챌린지 : 531-String to Union (medium) (0) | 2023.04.11 |
타입챌린지 : 529-Absolute (medium) (0) | 2023.04.10 |