Syncing account progress…

Back

Advanced · 18 min

Template literals and key remapping

Derive related string keys while preserving the corresponding property types.

Build constrained string names

Template literal types combine literal unions into new string unions. They can keep a small event-name convention consistent. They do not validate arbitrary runtime strings, and large unions can expand into many combinations.

type Field = "name" | "city";
type EventName = `${Field}Changed`;
const event: EventName = "cityChanged";
console.log(event);

Output

cityChanged

Rename keys in a mapped type

The "as" clause remaps keys. Intersecting a key with string allows string transformations, and the indexed access preserves each original value type. The example creates getter names in the type system; the functions still need implementations.

type Getters<T> = { [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K] };
type Profile = { name: string; score: number };
const getters: Getters<Profile> = { getName: () => "Ada", getScore: () => 7 };
console.log(getters.getName() + ": " + getters.getScore());

Output

Ada: 7

Put it into practice

  1. Predict the output and explain which relationships the types enforce.
  2. Fix the task while preserving its type contract, then check both practice questions.

Try it yourself

Code runs on this device. When you are signed in, drafts sync to your account.

Implement a correctly typed getter

Make "getScore" return the number 7, preserving the getter contract.

Show solution
type Getters<T> = { [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K] };
type Profile = { name: string; score: number };
const getters: Getters<Profile> = { getName: () => "Ada", getScore: () => 7 };
console.log(getters.getName() + ": " + getters.getScore());

Key remapping changes names without changing the associated value types. Returning a number satisfies the generated score getter contract.

Practice