[TypeScript] Type Challenges #612 - KebabCase

79 阅读1分钟

题目描述

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"

题解

// ============= Test Cases =============
import type { Equal, Expect } from './test-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<'😎'>, '😎'>>,
]


// ============= Your Code Here =============
type KebabCase<T extends string> =
  T extends `${infer Head}${infer Tail}`
      ? Tail extends Uncapitalize<Tail>
          ? `${Lowercase<Head>}${KebabCase<Tail>}`
          : `${Lowercase<Head>}-${KebabCase<Tail>}`
      : T;

类型约束

使用T extends stringT进行约束,确保T是一个字符串类型

条件类型

type KebabCase<T extends string> =
  T extends `${infer Head}${infer Tail}`
      ? Tail extends Uncapitalize<Tail>
          ? `${Lowercase<Head>}${KebabCase<Tail>}`
          : `${Lowercase<Head>}-${KebabCase<Tail>}`
      : T;
  • 如果T不是空字符串:

    • T extends ${infer Head}${infer Tail}

      • infer Head:将T的第一个字符推断为Head

      • infer Tail:将T的剩余字符串推断为Tail

    • Tail extends Uncapitalize<Tail>

      • 如果Tail以小写字母开头:

        • Head转换为小写,并递归调用KebabCase<Tail>
      • 如果Tail不是以小写字母开头:

        • Head转换为小写,并在后面拼接一个连接符-,然后递归调用KebabCase<Tail>
  • 如果T是空字符串:

    • 直接返回T