// your answers
type CapitalizeWords<S extends string, B extends boolean = true, T extends string = ''>
= S extends `${infer F}${infer R}`
? CapitalizeWords<R, (Uppercase<F> extends Lowercase<F> ? true : false), `${T}${B extends true ? Uppercase<F> : F}`>
: T
Solution by goddnsgit #36258
Here is a very verbose solution that I work out after many refactors:
type LowercaseLetters =
| "a" | "b" | "c" | "d" | "e" | "f"
| "g" | "h" | "i" | "j" | "k" | "l"
| "m" | "n" | "o" | "p" | "q" | "r"
| "s" | "t" | "u" | "v" | "w" | "x"
| "y" | "z" ;
type UppercaseLetters =
| "A" | "B" | "C" | "D" | "E" | "F"
| "G" | "H" | "I" | "J" | "K" | "L"
| "M" | "N" | "O" | "P" | "Q" | "R"
| "S" | "T" | "U" | "V" | "W" | "X"
| "Y" | "Z" ;
type ConvertLowerToUpper<T extends LowercaseLetters>
= T extends "a" ? "A" : T extends "b" ? "B" :
T extends "c" ? "C" : T extends "d" ? "D" :
T extends "e" ? "E" : T extends "f" ? "F" :
T extends "g" ? "G" : T extends "h" ? "H" :
T extends "i" ? "I" : T extends "j" ? "J" :
T extends "k" ? "K" : T extends "l" ? "L" :
T extends "m" ? "M" : T extends "n" ? "N" :
T extends "o" ? "O" : T extends "p" ? "P" :
T extends "q" ? "Q" : T extends "r" ? "R" :
T extends "s" ? "S" : T extends "t" ? "T" :
T extends "u" ? "U" : T extends "v" ? "V" :
T extends "w" ? "W" : T extends "x" ? "X" :
T extends "y" ? "Y" : T extends "z" ? "Z" :
never;
type ConvertUpperToLower<T extends UppercaseLetters>
= T extends "A" ? "a" : T extends "B" ? "b" :
T extends "C" ? "c" : T extends "D" ? "d" :
T extends "E" ? "e" : T extends "F" ? "f" :
T extends "G" ? "g" : T extends "H" ? "h" :
T extends "I" ? "i" : T extends "J" ? "j" :
T extends "K" ? "k" : T extends "L" ? "l" :
T extends "M" ? "m" : T extends "N" ? "n" :
T extends "O" ? "o" : T extends "P" ? "p" :
T extends "Q" ? "q" : T extends "R" ? "r" :
T extends "S" ? "s" : T extends "T" ? "t" :
T extends "U" ? "u" : T extends "V" ? "v" :
T extends "W" ? "w" : T extends "X" ? "x" :
T extends "Y" ? "y" : T extends "Z" ? "z" :
never;
type GetCapitalize<T extends string>
= T extends `${infer F}${infer Rest}`
? F extends LowercaseLetters
? `${ConvertLowerToUpper<F>}${Rest}`
: T
: T;
type CapitalizeWordsIgnoreFirst<T extends string>
= T extends `${infer F}${infer Rest}`
? F extends LowercaseLetters | UppercaseLetters
? `${F}${CapitalizeWordsIgnoreFirst<Rest>}` // When F is a letter, write F into the result normally
: Rest extends `${infer RF}${infer RR}`
? RF extends LowercaseLetters | UppercaseLetters
? RF extends LowercaseLetters
? `${F}${ConvertLowerToUpper<RF>}${CapitalizeWordsIgnoreFirst<RR>}`
: `${F}${RF}${CapitalizeWordsIgnoreFirst<RR>}`
: `${F}${CapitalizeWordsIgnoreFirst<Rest>}`
: Rest
: T;
type CapitalizeWords<T extends string> = GetCapitalize<CapitalizeWordsIgnoreFirst<T>>;
TypeScript treats the emoji as two code units, so the main problem in this challenge is continuous non-letters characters such as ||||
, \[
or just an emoji 🚀
.
And here is a bug (maybe not) that I encounter when I write this solution.
type TestEmojiR1 = "🤣" extends `${infer F}${infer R}` ? R : 1; // "�"
type TestEmojiF1 = "🤣" extends `${infer F}${infer R}` ? F : 1; // "�"
type TestEmoji1 = `${TestEmojiF1}${TestEmojiR1}` // "🤣"
type TestEmojiR1R = TestEmojiR1 extends `${infer F}${infer R}` ? R : 1; // ""
type TestEmojiR1F = TestEmojiR1 extends `${infer F}${infer R}` ? F : 1; // "�"
type TestEmojiR2 = "👩👩👦👦" extends `${infer F}${infer R}` ? R : 1; // �👩👦👦
type TestEmojiF2 = "👩👩👦👦" extends `${infer F}${infer R}` ? F : 1; // �
type TestEmojiR2F = TestEmojiR2 extends `${infer F}${infer R}` ? F : 1; // �
type TestEmoji2 = `${TestEmojiF2}${TestEmojiR2F}`; // 👩
// Reference
// [1]. https://github.com/microsoft/TypeScript/issues/61525
// [2]. https://github.com/microsoft/TypeScript/issues/41149
Solution by AshGreyG #36173
type IsAlphabet<S extends string> = Uppercase<S> extends Lowercase<S> ? false : true;
type CapitalizeWords<S extends string, Flag extends boolean = true, R extends string = ''> =
S extends `${infer First}${infer Rest}`
? IsAlphabet<First> extends true
? Flag extends true
? CapitalizeWords<Rest, false, `${R}${Uppercase<First>}`>
: CapitalizeWords<Rest, false, `${R}${First}`>
: CapitalizeWords<Rest, true, `${R}${First}`>
: R
Solution by gangnamssal #35976
type NotEnglistWord<T extends string> = Uppercase<T> extends Lowercase<T> ? true : false
type CapitalizeWords<S extends string, W extends string = ''> = S extends `${infer R}${infer rest}` ? (NotEnglistWord<R> extends true ? `${Capitalize<W>}${R}${CapitalizeWords<rest>}` : CapitalizeWords<rest, `${W}${R}`>) : Capitalize<W>
Solution by ouzexi #34211
// your answers
type IsNotEnglish<T extends string> = Uppercase<T> extends Lowercase<T> ? true : false;
type MyCapitalize<T extends string> = T extends `${infer F}${infer S}` ? `${Uppercase<F>}${S}` : T;
type Split<T extends string, Words extends string = ''> = T extends `${infer First}${infer Rest}`
? IsNotEnglish<First> extends true
? [`${MyCapitalize<Words>}${First}`, ...Split<Rest>]
: Split<`${Rest}`, `${Words}${First}`>
: [Capitalize<Words>];
type CapitalizeArray<T extends string[]> = T extends [infer F extends string, ...infer Rest extends string[]]
? [Capitalize<F>, ...CapitalizeArray<Rest>]
: [];
type Join<T extends string[]> = T extends [infer F extends string, ...infer Rest extends string[]]
? `${F}${Join<Rest>}`
: ''
type CapitalizeWords<T extends string> = Join<CapitalizeArray<Split<T>>>;
Solution by kakasoo #32976
// your answers
type IsNotEnglish<T extends string> = Uppercase<T> extends Lowercase<T> ? true : false;
type CapitalizeWords<T extends string, Words extends string = ''> = T extends `${infer First}${infer Rest}`
? IsNotEnglish<First> extends true
? `${Capitalize<Words>}${First}${CapitalizeWords<`${Rest}`>}`
: CapitalizeWords<`${Rest}`, `${Words}${First}`>
: `${Capitalize<Words>}`;
Solution by kakasoo #32975
不知道怎么判断是否是字母,用了最原始的方法,把它们全部列举出来 🤣🤣
type UpperLetter =
| "A"
| "B"
| "C"
| "D"
| "E"
| "F"
| "G"
| "H"
| "I"
| "J"
| "K"
| "L"
| "M"
| "N"
| "O"
| "P"
| "Q"
| "R"
| "S"
| "T"
| "U"
| "V"
| "W"
| "X"
| "Y"
| "Z";
type LowerLetter =
| "a"
| "b"
| "c"
| "d"
| "e"
| "f"
| "g"
| "h"
| "i"
| "j"
| "k"
| "l"
| "m"
| "n"
| "o"
| "p"
| "q"
| "r"
| "s"
| "t"
| "u"
| "v"
| "w"
| "x"
| "y"
| "z";
type CapitalizeWords<
S extends string,
Flag extends boolean = true
> = S extends `${infer L}${infer Rest}`
? L extends UpperLetter | LowerLetter
? Flag extends true
? `${Capitalize<L>}${CapitalizeWords<Rest, false>}`
: `${L}${CapitalizeWords<Rest, false>}`
: `${L}${CapitalizeWords<Rest, true>}`
: "";
Solution by Vampirelee #32606
type CapitalizeWords<T extends string> = T extends `${infer Word} ${infer Rest}` ? `${Capitalize<Word>} ${CapitalizeWords<Rest>}` : Capitalize<T>;
Solution by PCOffline #31067
This CapitalizeWords
cannot cut words recursively:
/* _____________ Your Code Here _____________ */
type LowercaseEnglishArray = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
type UppercaseEnglishArray = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
type LowercaseEnglishUnion = LowercaseEnglishArray[number]
type UppercaseEnglishUnion = UppercaseEnglishArray[number]
type EnglishWord<S extends string> = S extends `${infer C extends LowercaseEnglishUnion | UppercaseEnglishUnion}${infer RestString extends string}`
? `${C}${EnglishWord<RestString>}`
: ''
type CapitalizeWord<S extends string> = S extends `${infer W extends EnglishWord<S>}` | `${infer W extends EnglishWord<S>}${infer Rest extends string}`
? W extends `${infer FirstChar extends LowercaseEnglishUnion | UppercaseEnglishUnion}${infer RestChars extends string}`
? `${Uppercase<FirstChar>}${RestChars}`
: ''
: ''
type Shift<T extends string> = T extends `${infer First}${infer Rest extends string}`
? Rest
: ''
type CapitalizeWords<S extends string> = S extends `${infer W extends EnglishWord<S>}${infer RestString extends string}`
? `${CapitalizeWord<W>}${RestString[0]}${CapitalizeWords<Shift<RestString>>}`
: S extends `${infer W extends EnglishWord<S>}`
? `${CapitalizeWord<W>}`
: CapitalizeWords<Shift<S>>;
/* _____________ Test Cases _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<LowercaseEnglishArray['length'], 26>>,
Expect<Equal<UppercaseEnglishArray['length'], 26>>,
Expect<Equal<'f' extends LowercaseEnglishUnion ? true : false, true>>,
Expect<Equal<Uppercase<'f'>, 'F'>>,
Expect<Equal<Uppercase<'foo bar'>, 'FOO BAR'>>,
Expect<Equal<EnglishWord<'foobar'>, 'foobar'>>,
Expect<Equal<EnglishWord<'foobar hello world'>, 'foobar'>>,
Expect<Equal<CapitalizeWord<'foobar'>, 'Foobar'>>,
Expect<Equal<CapitalizeWord<'FOOBAR'>, 'FOOBAR'>>,
Expect<Equal<CapitalizeWord<'foo bar'>, ''>>,
Expect<Equal<Shift<''>, ''>>,
Expect<Equal<Shift<'321'>, '21'>>,
Expect<Equal<Shift<'abcd'>, 'bcd'>>,
Expect<Equal<CapitalizeWords<'foobar'>, 'Foobar'>>,
Expect<Equal<CapitalizeWords<'FOOBAR'>, 'FOOBAR'>>,
Expect<Equal<CapitalizeWords<'foobar '>, 'Foobar '>>,
Expect<Equal<CapitalizeWords<'foo bar'>, 'Foo Bar'>>,
Expect<Equal<CapitalizeWords<'foo bar hello world'>, 'Foo Bar Hello World'>>,
Expect<Equal<CapitalizeWords<'foo bar.hello,world'>, 'Foo Bar.Hello,World'>>,
Expect<Equal<CapitalizeWords<'aa!bb@cc#dd$ee%ff^gg&hh*ii(jj)kk_ll+mm{nn}oo|pp🤣qq'>, 'Aa!Bb@Cc#Dd$Ee%Ff^Gg&Hh*Ii(Jj)Kk_Ll+Mm{Nn}Oo|Pp🤣Qq'>>,
Expect<Equal<CapitalizeWords<''>, ''>>,
]
Solution by KNHui #30994
type CapitalizeWords<T extends string, S extends string = ''> = T extends `${infer W} ${infer O}` ? CapitalizeWords<O, `${S}${Capitalize<W>} `> : `${S}${Capitalize<T>}`
Solution by HenrryShaw #27754
// 空字符串情况
type Space = "" | " " | "\n" | "\t"
// Head 为虚拟头节点,默认为 ""
// 不仅要判断头节点为空!还要判断下一个节点是否为空
type CapitalizeWords<S extends string, Head extends string = "", W extends string = ""> =
S extends `${infer L}${infer R}` ? Head extends Space ? L extends Space ?
CapitalizeWords<Lowercase<R>, L, `${W}`> :
CapitalizeWords<Lowercase<R>, L, `${W}${Uppercase<L>}`> : CapitalizeWords<Lowercase<R>, L, `${W}${L}`> : W
Solution by wuxin0011 #27563
// 思路:将遍历的字母存到W中,直到遇到非字母时,取出W进行Capitalize,再清空W再进行搜集处理
type CapitalizeWords<
S extends string,
W extends string = ''
> = S extends `${infer A}${infer B}`
? Uppercase<A> extends Lowercase<A>
? `${Capitalize<`${W}${A}`>}${CapitalizeWords<B>}`
: CapitalizeWords<B, `${W}${A}`>
: Capitalize<W>
Solution by smileboyi #27495
type CapitalizeWords<
S extends string,
W extends string = ''
> = S extends `${infer A}${infer B}`
? Uppercase<A> extends Lowercase<A>
? `${Capitalize<`${W}${A}`>}${CapitalizeWords<B>}`
: CapitalizeWords<B, `${W}${A}`>
: Capitalize<W>
Solution by smileboyi #27457
type IsLetter<T extends string> = Uppercase<T> extends Lowercase<T>
? false
: true; // check that is difference between uppercase and lowercase
type CapitalizeWords<S extends string, PrevLetter extends string = ' '> = [
S,
] extends [`${infer CurrentLetter}${infer Tail}`]
? IsLetter<PrevLetter> extends false
? `${Capitalize<CurrentLetter>}${CapitalizeWords<Tail, CurrentLetter>}`
: `${CurrentLetter}${CapitalizeWords<Tail, CurrentLetter>}`
: '';
Solution by jakubjereczek #26659
type CapitalizeWords<
S extends string,
Word extends string = '',
Words extends string = ''
> = S extends `${infer F}${infer R}`
? Uppercase<F> extends Lowercase<F>
? CapitalizeWords<R, '', `${Words}${Word}${F}`>
: Word extends ''
? CapitalizeWords<R, `${Word}${Uppercase<F>}`, Words>
: CapitalizeWords<R, `${Word}${F}`, Words>
: `${Words}${Word}`;
Solution by JohnLi1999 #25241
// your answers
type CapitalizeWords<S extends string, W extends string = ''> = S extends `${infer Left}${infer Rest}`
? Uppercase<Left> extends Lowercase<Left>
? `${Capitalize<W>}${Left}${CapitalizeWords<Rest>}`
: CapitalizeWords<Rest, `${W}${Left}`>
: Capitalize<W>
Solution by studymachiney #24965
// your answers
type isAlphabet<T extends string> =
Uppercase<T> extends Lowercase<T> ? false
: true
;
type CapitalizeWord<W extends string> =
W extends `${infer CW}${infer CR}` ?
CW extends Uppercase<CW> ? W
: `${Uppercase<CW>}${CR}`
: W
;
type CapitalizeWords<S extends string, Result extends string = ''> =
S extends `${infer C}${infer R}` ?
isAlphabet<C> extends false ?
R extends `${infer CW}${infer CR}` ?
isAlphabet<CW> extends true ? CapitalizeWords<CR, `${Result}${C}${Uppercase<CW>}`>
: CapitalizeWords<R, `${Result}${C}`>
: CapitalizeWord<Result>
: CapitalizeWords<R, `${Result}${C}`>
: CapitalizeWord<Result>
;
Solution by MrNinso #24936
type Whitespace = ' '| ',' | '.'
type CapitalizeWords<S extends string, O extends string = ''> = S extends `${infer F}${infer Rest}`
? CapitalizeWords<Rest, CombineStr<F, O>>
: MyCapitalize<CombineStr<S, O>>
type CombineStr<S extends string, O extends string> = O extends `${infer _F}${Whitespace}` ? `${O}${Uppercase<S>}`: `${O}${S}`
type MyCapitalize<S extends string> = S extends `${infer F}${infer Rest}`
? `${Uppercase<F>}${Rest}`
: S
Solution by GDCzhou #24800
type IsAlphabet<T extends string> = Lowercase<T> extends Uppercase<T> ? false : true;
type GetUpper<T extends string, IsFirst extends boolean> = IsFirst | IsAlphabet<T> extends true ? Uppercase<T> : T;
type GetIsFirst<Pre extends string> = IsAlphabet<Pre> extends true ? false : true;
//平铺式
type CapitalizeWords<S extends string, _IsFirst extends boolean = true> = S extends `${infer F}${infer Sec/*Too Deep Solution*/}${infer R}` ?
(`${GetUpper<F, _IsFirst>}${GetUpper<Sec, GetIsFirst<F>>}${CapitalizeWords<R, GetIsFirst<Sec>>}`) :
GetUpper<S, _IsFirst>;
//暂存式
// type CapitalizeWords<S extends string, _IsFirst extends boolean = true, _Result extends string/*Too Deep Solution*/ = ``> = S extends `${infer F}${infer R}` ?
// (CapitalizeWords<R, GetIsFirst<F>, `${_Result}${GetUpper<F, _IsFirst>}`>) :
// _Result;
Solution by E-uler #24686
type IsLetter<T extends string> = Uppercase<T> extends T ? false : true
type CapitalizeWords<
S extends string,
NewWord extends boolean = true,
NewString extends string = ''
> = S extends `${infer First}${infer Rest}`
? IsLetter<First> extends true
? NewWord extends true
? CapitalizeWords<Rest, false, `${NewString}${Uppercase<First>}`>
: CapitalizeWords<Rest, false, `${NewString}${First}`>
: CapitalizeWords<Rest, true, `${NewString}${First}`>
: NewString
Solution by NeylonR #24418
// Using a Result variable to hold the result as the type instantiation would be too deep otherwise
type CapitalizeWords<S extends string, PartOfWord = false, Result extends string = ''> =
S extends `${infer Pre}${infer Rest}`
?
Pre extends Uppercase<Pre> ? CapitalizeWords<Rest, false, `${Result}${Uppercase<Pre>}`>
: PartOfWord extends true ? CapitalizeWords<Rest, true, `${Result}${Pre}`> :
CapitalizeWords<Rest, true, `${Result}${Uppercase<Pre>}`>
: Result
Solution by flavianh #24359
// 你的答案
// 判断分隔符
type IsDelimiter<S extends string> = Lowercase<S> extends
'a'|'b'| 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j'
| 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's'
| 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z'
| '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
? false : true ;
/**
* @param {string }R 上次计算的结果 用来解决防止递归次数过大
*/
type CapitalizeWords<S extends string,Delimiter extends string = '.',R extends string = ''> = S extends `${infer F extends string}${infer O extends string}`
? IsDelimiter<Delimiter> extends true
? CapitalizeWords<O,F,`${R}${Capitalize<F>}`>
:CapitalizeWords<O,F,`${R}${F}`>
:R;
Solution by walker-hzx #24300
type isLetter<T extends string> = Uppercase<T> extends Lowercase<T> ? false : true;
type CapitalizeWords<S extends string, Exc extends boolean = true, R extends string = ''> = S extends `${infer F}${infer O}`
? isLetter<F> extends true
? Exc extends true
? CapitalizeWords<O, false, `${R}${Uppercase<F>}`>
: CapitalizeWords<O, false, `${R}${F}`>
: CapitalizeWords<O, true, `${R}${F}`>
: R;
Solution by sabercc #23871
// your answers 参考楼下
type NotLetter<T extends string> = Uppercase<T> extends Lowercase<T> ? true : false;
type CapitalizeWords<
S extends string,
U extends string = "",
Cap = true
> = S extends `${infer F}${infer R}`
? Cap extends true
? CapitalizeWords<R, `${U}${Capitalize<F>}`, NotLetter<F>>
: CapitalizeWords<R, `${U}${F}`, NotLetter<F>>
: U;
Solution by snakeUni #23442
type NotLetter<T extends string> = Uppercase<T> extends Lowercase<T> ? true : false;
type CapitalizeWords<
S extends string,
U extends string = "",
Cap = true
> = S extends `${infer F}${infer R}`
? Cap extends true
? CapitalizeWords<R, `${U}${Capitalize<F>}`, NotLetter<F>>
: CapitalizeWords<R, `${U}${F}`, NotLetter<F>>
: U;
Solution by coderyoo1 #23015
// 你的答案
type IsLetter<T extends string> = Uppercase<T> extends Lowercase<T> ? true : false;
type CapitalizeWords_<
S extends string,
R extends string = ""
> = S extends `${infer First}${infer Rest}`
? IsLetter<First> extends true
? `${Capitalize<`${R}${First}`>}${CapitalizeWords_<Rest>}`
: CapitalizeWords_<Rest, `${R}${First}`>
: Capitalize<R>
type CapitalizeWords<S extends string> = Capitalize<CapitalizeWords_<S>>
Solution by jxhhdx #22821
type CapitalizeWords<T extends string, B extends boolean = false> =
T extends `${infer F}${infer R}`
? F extends ' ' | '.' |','
? R extends `${infer F1}${infer R1}` ? `${F}${Uppercase<F1>}${CapitalizeWords<R1,true>}` : R
: `${B extends false ? Uppercase<F> : F}${CapitalizeWords<R,true>}`
: T
Solution by TKBnice #22695
type IsNotLetter<S extends string> = Uppercase<S> extends Lowercase<S> ? true : false;
type CapitalizeWords_<S extends string, R extends string = ""> = S extends `${infer First}${infer Rest}`
? IsNotLetter<First> extends true
? `${Capitalize<`${R}${First}`>}${CapitalizeWords_<Rest>}`
: CapitalizeWords_<Rest, `${R}${First}`>
: Capitalize<R>
type CapitalizeWords<S extends string> = Capitalize<CapitalizeWords_<S>>
Solution by kfess #22245
type IsLetter<T extends string> = Uppercase<T> extends Lowercase<T> ? false : true
type CapitalizeWords<S extends string, R extends string = '', Temp extends string = ''> =
S extends `${infer A}${infer Rest}`
? IsLetter<A> extends true
? CapitalizeWords<Rest, R, `${Temp}${A}`>
: CapitalizeWords<Rest, `${R}${Capitalize<Temp>}${A}`>
: `${R}${Capitalize<Temp>}`
Solution by drylint #22199
// your answers
type IsZimu<T extends string> = Uppercase<T> extends Lowercase<T> ? false : true
type CapitalizeWords<S extends string, Trans extends boolean = true, R extends string = ''> = S extends `${infer First}${infer Rest}`
? IsZimu<First> extends true
? Trans extends true
? CapitalizeWords<Rest, false, `${R}${Uppercase<First>}`>
: CapitalizeWords<Rest, false, `${R}${First}`>
: CapitalizeWords<Rest, true, `${R}${First}`>
: R
Solution by 437204933 #22045