TypeScriptUtility types

Uppercase, Lowercase, Capitalize, Uncapitalize

Built-in types that change letter case in text types, e.g. "gold" to "GOLD".

On this page

Example

#
TypeScript
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)
Result
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

#
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

#
Event handler names
TypeScript
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 })
Result
Start: Grid
Finish: Grid, +15 EXP
Uppercase<string> as a constraint
TypeScript
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() or toLowerCase(), and you ensure it matches the type with an assertion, as in the capitalize function 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_case to camelCase, these types arenโ€™t enough. You need your own type built from infer and template literal types.

Related entries

#

Spotted a mistake or missing an example? Write to us.