00612-medium-kebabcase

Back

interface UpperChars {
  '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, ACC extends string = ''> = S extends '-' ? S 
  : S extends `${infer First extends keyof UpperChars}${infer Rest}` 
    ? KebabCase<Rest, `${ACC}-${UpperChars[First]}`> 
    : S extends `${infer First}${infer Rest}` 
      ? KebabCase<Rest, `${ACC}${First}`> 
      : ACC extends `-${infer Result}` ? Result : ACC

Solution by eunsukimme #35241

type KebabCase<
  T extends string,
  P extends string = ""
> = T extends `${infer L}${infer Rest}`
  ? Equal<Lowercase<L>, L> extends true
    ? `${L}${KebabCase<Rest, L>}`
    : `${P extends "" ? P : "-"}${Lowercase<L>}${KebabCase<Rest, L>}`
  : T;

Solution by wan-kong #35104

type KebabCase<
  T extends string,
  K extends string = "",
> = T extends `${infer L}${infer R}`
  ? L extends Lowercase<L>
    ? KebabCase<R, `${K}${L}`>
    : KebabCase<R, `${K}${K extends "" ? "" : "-"}${Lowercase<L>}`>
  : K;

Solution by Artawower #34840

type KebabCase<S extends string> = S extends `${infer First}${infer Rest}`? Rest extends Uncapitalize<Rest> ? `${Uncapitalize<First>}${KebabCase<Rest>}` : `${Uncapitalize<First>}-${KebabCase<Rest>}` : S

Solution by devshinthant #34611

type KebabCase<
  S extends string,
  Previous extends string = ""
> = S extends `${infer First}${infer Rest}`
  ? Lowercase<First> extends First
    ? `${First}${KebabCase<Rest, First>}`
    : Previous extends ""
    ? `${Lowercase<First>}${KebabCase<Rest, First>}`
    : `-${Lowercase<First>}${KebabCase<Rest, First>}`
  : "";

Solution by yukicountry #34389

使用工具类型 Uncapitalize: Uncapitalize // 将 字符串 T 的第一个元素变成小写

type KebabCase<T extends string> =
T extends `${infer A}${infer B}`?
B extends Uncapitalize<B>? `${Uncapitalize<A>}${KebabCase<B>}` : `${Uncapitalize<A>}-${KebabCase<B>}`
:T

Solution by Jayce-liang #34283

type KebabCase<S extends string> = S extends `${infer R}${infer rest}` ? (rest extends Uncapitalize<rest> ? `${Uncapitalize<R>}${KebabCase<Uncapitalize<rest>>}` : `${Uncapitalize<R>}-${KebabCase<Uncapitalize<rest>>}`) : S

Solution by ouzexi #34021

type KebabCase<S extends string> = S extends `${infer S1}${infer S2}${infer S3}`
	? S2 extends Lowercase<S2>
		? `${Lowercase<S1>}${KebabCase<`${S2}${S3}`>}`
		: `${Lowercase<S1>}-${KebabCase<`${Lowercase<S2>}${S3}`>}`
	: S

Solution by waysjd #34003

612 - KebabCase

by Johnson Chu (@johnsoncodehk) #medium #template-literal

Question

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"

View on GitHub: https://tsch.js.org/612

...

type KebabCase<S extends string, F = S[0]> = S extends `${infer L}${infer R}`
  ? R extends Uncapitalize<R>
    ? `${Uncapitalize<L>}${KebabCase<R>}`
    : `${Uncapitalize<L>}-${KebabCase<R>}`
  : S

Solution by veralex #33802

解决两个问题:
1. 如何判断是否为大写字母
T extends Uppercase<T> 为true 同时 T extends Lowercase<T> 为false,则该字母为大写字母
2. 是否为首字母
默认为true,其他传值为false


// 判断是否为大写字母
type isUpperLetter<T extends string> = T extends Uppercase<T> 
? T extends Lowercase<T>
  ? false
  : true
: false;

type KebabCase<S, IsFirst = true> = S extends `${infer L}${infer R}` 
? `${isUpperLetter<L> extends true ? IsFirst extends true ? '' : '-' : ''}${Lowercase<L>}${KebabCase<R, false>}`
: S;

Solution by chenghao125 #33432

// 判断是否为大写字母
type isUpperLetter<T extends string> = T extends Uppercase<T> 
? T extends Lowercase<T>
  ? false
  : true
: false;

type KebabCase<S, IsFirst = true> = S extends `${infer L}${infer R}` 
? `${isUpperLetter<L> extends true ? IsFirst extends true ? '' : '-' : ''}${Lowercase<L>}${KebabCase<R, false>}`
: S;

Solution by chenghao125 #33431

// your answers
type KebabCase<S> = S extends `${infer R}${infer T}`
  ? `${Uncapitalize<R>}${T extends Uncapitalize<T> ? "" : "-"}${KebabCase<T>}`
  : S

The KebabCase type recursively breaks down a string into its first character and the rest, converting the first character to lowercase and adding a hyphen before any uppercase letters in the rest of the string. This process continues until the entire string is transformed into kebab-case

Solution by lezhu1234 #33284

interface Hi{ 'A':'a'; 'B':'b'; 'F':'f'; }

type KebabCaseMy<T extends string, D extends string =''> = D extends '' ? T extends ${infer C extends keyof Hi}${infer R} ? KebabCaseMy<R,${D}${Hi[C]}> : T extends ${infer C}${infer R} ? KebabCaseMy<R,${D}${C}> :D :T extends ${infer C extends keyof Hi}${infer R} ? KebabCaseMy<R,${D}-${Hi[C]}> : T extends ${infer C}${infer R} ? KebabCaseMy<R,${D}${C}> : D;

Solution by Shlufman #33083

type UnCapitalize<S extends string> = S extends `${infer F}${infer R}`
  ? `${Lowercase<F>}${R}`
  : ''

type KebabCase<S extends string, Acc extends string = ''> = S extends `${infer F}${infer R}`
  ? R extends UnCapitalize<R>
    ? KebabCase<R, `${Acc}${F}`>
    : `${UnCapitalize<`${Acc}${F}`>}-${KebabCase<R>}`
  : UnCapitalize<Acc>

Solution by rimo030 #32980


type UpperMap = {
  '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 Upper = keyof UpperMap

type Step1<S extends string> = S extends `${infer Cap}${infer Rest}` ? Cap extends Upper ? `${UpperMap[Cap]}${Rest}` : S : S

type Step2<S extends string, A extends string = ''> = S extends `${infer Cap}${infer Rest}` ? Cap extends Upper ? Step2<Rest, `${A}-${UpperMap[Cap]}`> : Step2<Rest, `${A}${Cap}`> : A

type KebabCase<S extends string> = Step2<Step1<S>>

Solution by ZJia1231 #32489

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 유틸리티 타입

Solution by dev-hobin #32417

// your answers
type KebabCase<S extends string> = S extends `${infer L}${infer R}`
? R extends Uncapitalize<R>
  ? `${Uncapitalize<L>}${KebabCase<R>}`
  : `${Uncapitalize<L>}-${KebabCase<R>}`
  : S;

Solution by pea-sys #32355

type KebabCase<S extends string, U extends string = S> = U extends `${infer F}${infer L}`
	? L extends ""
		? F extends ToUpperCase
			? S extends `${infer F1}${F}`
				? F1 extends ""
					? `${LowerCase[F]}`
					: `${F1}-${LowerCase[F]}`
				: never
			: S
		: F extends ToUpperCase
		? KebabCase<
				S extends `${infer F2}${F}${infer L1}`
					? F2 extends ""
						? `${LowerCase[F]}${L1}`
						: `${F2}-${LowerCase[F]}${L1}`
					: S,
				L
		  >
		: KebabCase<S, L>
	: "";

interface LowerCase {
	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 ToUpperCase = keyof LowerCase;

Solution by gasmg #32002

type KebabCase<S> = S extends `${infer S1}${infer S2}`
  ? S2 extends Uncapitalize<S2>
    ? `${Uncapitalize<S1>}${KebabCase<S2>}`
    : `${Uncapitalize<S1>}-${KebabCase<S2>}`
  : S;

Solution by jinyoung234 #31937

type KebabCase<S> = S extends `${infer S1}${infer S2}` 
  ? S2 extends Uncapitalize<S2> ? `${Uncapitalize<S1>}${KebabCase<Uncapitalize<S2>>}` : `${Uncapitalize<S1>}-${KebabCase<Uncapitalize<S2>>}`
  : S;

Solution by kai-phan #31657

type KebabCase<S extends string> = S extends `${infer S1}${infer S2}`
  ? S2 extends Uncapitalize<S2>
  ? `${Uncapitalize<S1>}${KebabCase<S2>}`
  : `${Uncapitalize<S1>}-${KebabCase<S2>}`
  : S;

Solution by vipulpathak113 #31515

type KebabCase<S extends string> = S extends `${infer S1}${infer S2}`
  ? S2 extends Uncapitalize<S2>
  ? `${Uncapitalize<S1>}${KebabCase<S2>}`
  : `${Uncapitalize<S1>}-${KebabCase<S2>}`
  : S;

Solution by MyeonghoonNam #31440

type KebabCase<S extends string, P extends string = ''> = 
  S extends `${infer A}${infer Rest}`
    ? Lowercase<A> extends Uppercase<A>
      ? `${A}${KebabCase<Rest, '-'>}`
      : `${A extends Uppercase<A> ? `${P}${Lowercase<A>}` : A}${KebabCase<Rest, '-'>}`
  : S;

Solution by ricky-fn #31337

type Uppers = {
  F:'f',
  B:'b',
  C:'c',
  A:'a',
  //...
}
type KebabCase<S extends string, Tmp extends string = ""> = S extends `${infer A}${infer B}` ? KebabCase<B, `${Tmp}${A extends keyof Uppers ? `${Tmp extends '' ? '':'-'}${Uppers[A]}` : A}`> : Tmp;

Solution by eward957 #31251

// your answers

type KebabCase<S> = S extends `${infer First}${infer Rest}`
  ? Rest extends Uncapitalize<Rest>
    ? `${Lowercase<First>}${KebabCase<Rest>}`
    : `${Lowercase<First>}-${KebabCase<Rest>}`
  : S;

Solution by d1zzzzy #31230

// your answers
type KebabCase<S extends string,  Pre extends string = ''> = S extends `${infer L}${infer Rest}` ? (
  L extends Lowercase<L> ? KebabCase<Rest, `${Pre}${L}`> : (
    (Pre extends '' ? KebabCase<Rest, `${Lowercase<L>}`> 
    : KebabCase<Rest, `${Pre}-${Lowercase<L>}`>)
  )
): Pre;

Solution by CDSP98 #31031

type KebabCase<S, P = S> = S extends `${infer C}${infer R}`
  ? IsUppercase<C> extends true
    ? `${C}${R}` extends `${infer ST}` // is uppercase letters
      ? `${ST extends P /* is first letters */ ? '' : '-'}${Lowercase<C>}${KebabCase<R, P>}`
      : never
    : `${C}${KebabCase<R, P>}`
  : S // single letters

type IsUppercase<T extends string> = T extends Uppercase<T>
  ? T extends Lowercase<T>
    ? false
    : true
  : false

Solution by Chan-Yuxi #30558

type KebabCase<S extends string, R extends string = ''> = S extends '' 
  ? R
  : S extends `${infer F}${infer Rest}` 
    ? KebabCase<Rest, `${R}${F extends Uppercase<F> ? (Lowercase<F> extends F ? '' : R extends '' ? '' : '-') : ''}${Lowercase<F>}`>
    : R;

Solution by kai-phan #30378

type KebabCase<S extends string> =
  S extends `${infer L}${infer R}`
    ? R extends '' | `${Lowercase<string>}${string}`
      ? `${Lowercase<L>}${KebabCase<R>}`
      : `${Lowercase<L>}-${KebabCase<R>}`
    : ''

or

type KebabCase<S extends string> =
  S extends `${infer L}${infer R}`
    ? R extends Uncapitalize<R>
      ? `${Uncapitalize<L>}${KebabCase<R>}`
      : `${Uncapitalize<L>}-${KebabCase<R>}`
    : ''

Solution by sbr61 #29972

type KebabCase<S extends string, T = Uncapitalize<S>> = T extends `${infer R}${infer P}`
    ? P extends Uncapitalize<P>
        ? `${R}${KebabCase<P>}`
        : `${R}-${KebabCase<P>}`
    : T

Solution by lovezhangchuangxin #29962