Uppercase, Lowercase, Capitalize, Uncapitalize
Built-in types that change letter case in text types, e.g. "gold" to "GOLD".
Example
#type Rank = 'bronze' | 'silver' | 'gold'
type RankConstant = Uppercase<Rank>
// type RankConstant = "BRONZE" | "SILVER" | "GOLD"
function capitalize<S extends string>(text: S): Capitalize<S> {
return (text.charAt(0).toUpperCase() + text.slice(1)) as Capitalize<S>
}
const label = capitalize('silver')
// const label: "Silver"
const constant: RankConstant = 'GOLD'
console.log(label, constant)Silver GOLD
Definition and usage
#Four built-in types change the letter case of literal types. Uppercase turns every letter uppercase, Lowercase turns every letter lowercase, Capitalize turns only the first letter uppercase, and Uncapitalize turns the first letter lowercase. They also work on unions: Uppercase<"html" | "css"> is "HTML" | "CSS".
A transformation like that canโt be written with ordinary types, which is why the compiler computes the result itself (hence the name intrinsic). These types only work at compile time. At runtime, you still have to change the case separately, e.g. with the toUpperCase() method, and you usually mark the result with an as assertion.
Theyโre most useful combined with template literal and mapped types: from the event name start you can build the handler name onStart, and from the rank "gold" the constant "GOLD". Used with plain string, they act as a filter: Uppercase<string> only accepts a string that stays unchanged after being converted to uppercase.
Syntax
#type A = Uppercase<"html"> // "HTML"
type B = Lowercase<"CSS"> // "css"
type C = Capitalize<"level"> // "Level"
type D = Uncapitalize<"Title"> // "title"Four types
#Uppercase<S>
"gold" โ "GOLD"
All letters uppercase.Lowercase<S>
"HTML" โ "html"
All letters lowercase.Capitalize<S>
"level" โ "Level"
First letter uppercase, the rest unchanged.Uncapitalize<S>
"Title" โ "title"
First letter lowercase, the rest unchanged.
More examples
#type LessonEvents = {
start: { lesson: string }
finish: { lesson: string; exp: number }
}
type Handlers = {
[K in keyof LessonEvents as `on${Capitalize<K>}`]: (event: LessonEvents[K]) => void
}
// type Handlers = {
// onStart: (event: { lesson: string }) => void
// onFinish: (event: { lesson: string; exp: number }) => void
// }
const handlers: Handlers = {
onStart: (e) => console.log(`Start: ${e.lesson}`),
onFinish: (e) => console.log(`Finish: ${e.lesson}, +${e.exp} EXP`)
}
handlers.onStart({ lesson: 'Grid' })
handlers.onFinish({ lesson: 'Grid', exp: 15 })Start: Grid Finish: Grid, +15 EXP
const courseCode: Uppercase<string> = 'HTML-1'
const wrongCode: Uppercase<string> = 'html-1'
// Error: Type 'string' is not assignable to type 'Uppercase<string>'.Good practices
#- These types donโt change the value. In running code you still need
toUpperCase()ortoLowerCase(), and you ensure it matches the type with an assertion, as in thecapitalizefunction from the example. - Only letters change.
Capitalize<"3d-model">stays the same, because the first character is a digit. - For changing notation, e.g.
snake_casetocamelCase, these types arenโt enough. You need your own type built frominferand template literal types.
Related entries
#- Template literal typesString types built from templates, like `${A}-${B}`.
- Mapped typesCreate a new object type by transforming every key of another type.
- Literal typesTypes that allow only specific values, e.g. "easy" | "hard".
- keyofCreates a union of the key names of a given object type.
- inferPulls a type out from inside another type, within a conditional type.
Spotted a mistake or missing an example? Write to us.