挑战
Replace the camelCase or PascalCase string with kebab-case.
FooBarBaz -> foo-bar-baz
For example
type FooBarBaz = KebabCase<'FooBarBaz'>;
const foobarbaz: FooBarBaz = 'foo-bar-baz';
type DoNothing = KebabCase<'do-nothing'>;
const doNothing: DoNothing = 'do-nothing';解答
像很多字符串题目一样,我们还是从推断首字母和剩下的字符串开始。
type KebabCase<S> = S extends `${infer C}${infer T}` ? never : never;一旦未匹配到就意味着我们全部转换完成。我们只需要原样返回输入的字符串。
type KebabCase<S> = S extends `${infer C}${infer T}` ? never : S;但是,一旦匹配到我们就需要处理 2 种情况。一种情况是没有首字母大写的尾部,一种情
况是有。为了检测这个,我们可以用内置类型 Uncapitalize。
type KebabCase<S> = S extends `${infer C}${infer T}`
? T extends Uncapitalize<T>
? never
: never
: S;如果我们有非首字母大写的尾部怎么办?假设我们有 “Foo” 或 “foo”,我们将首字母变成 小写,尾部保持不变。不要忘了继续处理剩余的字符串。
type KebabCase<S> = S extends `${infer C}${infer T}`
? T extends Uncapitalize<T>
? `${Uncapitalize<C>}${KebabCase<T>}`
: never
: S;现在剩下的情况就是有首字母大写的尾部,比如“fooBar”。我们需要将首字母变小写,然后
是连字符(-),然后继续递归的处理尾部。我们不需要使尾部首字母小写的原因是因为
Uncapitalize<C> 始终会使它变小写。
type KebabCase<S> = S extends `${infer C}${infer T}`
? T extends Uncapitalize<T>
? `${Uncapitalize<C>}${KebabCase<T>}`
: `${Uncapitalize<C>}-${KebabCase<T>}`
: S;