Key Remapping with as
Advanced · 18 min read · ▶ live playground · ✦ checkpoint
Key remapping lets a mapped type walk one set of keys and emit a different set of keys. [K in keyof T as NewKey] means: visit each original key K, then use the as clause to decide the property name in the new object type.
This as is not a type assertion or cast. It is mapped-type syntax only: the key on the left is being renamed before the new property is written.
Rename While Mapping
Last lesson's mapped type copied keys exactly:
type SameKeys<T> = {
[K in keyof T]: T[K];
};Key remapping adds one slot:
type StillSameKeys<T> = {
[K in keyof T as K]: T[K];
};as K says "emit the same key you are currently visiting," so this version still copies the shape. The useful move is to make the as expression conditional.
The loop still visits user_id, display_name, created_at, and active. The as clause chooses the output key for each one. The value side still uses T[K], so active remains boolean and createdAt remains string even though the property name changed.
Filtering Keys With never
In 10.3, never filtered union members out of conditional types. In key remapping, never filters properties out of the new object type.
There is an important distinction hiding here. A property value type of never would still create a property, just one no real value can fill. A remapped key of never removes the property from the resulting shape.
Getter Factories
Key remapping can also generate method names. This is the one place today where we need a tiny preview of next lesson's template literal types:
type Getters<T> = {
[K in keyof T as `get${Capitalize<K & string>}`]: () => T[K];
};Focus on the mapped-type shape, not the string machinery. The loop visits name; the new key becomes getName; the value type becomes () => T["name"]. The loop visits age; the new key becomes getAge; the value type becomes () => T["age"]. Capitalize and the template string are 11.3's deeper topic.
This is why remapping is more than cosmetic renaming. The output key changed from age to getAge, but the value side still knows it came from the original age property.
Real-World Sightings
You will see this pattern inside libraries that derive many related shapes from one source of truth.
An ORM might start with a table shape, then remap database column names like created_at to app-facing createdAt, or filter server-managed columns like id and createdAt out of an insert shape by mapping those keys to never.
A form library might start with a data model and derive field helpers, getter names, validation flags, or dirty-state maps from the same keys. The point is not that every library literally uses the aliases from this lesson. The point is the design move: one original shape, then mapped types produce synchronized API shapes so the names cannot drift apart by hand.
Key remapping chooses new property names while a mapped type walks the original keys. Next lesson makes those names more programmable: template literal types build string keys like getName, event names, and route fragments from smaller string types.
Checkpoint
Answer all three to mark this lesson complete