Careeroza
Key Remapping with as
Renaming Keys
TypeScript 4.1 added as in mapped types to rename or filter keys. Combine it with template literal types and Capitalize. Mapping a key to never removes it.
Example
type Product = { id: number; name: string; price: number; internalNotes: string };
type Getters<T> = { [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K] };
type WithoutInternal<T> = { [K in keyof T as K extends `internal${string}` ? never : K]: T[K] };
type OnlyNumbers<T> = { [K in keyof T as T[K] extends number ? K : never]: T[K] };
const p: Product = { id: 1, name: "Kettle", price: 1299, internalNotes: "supplier margin 12%" };
const getters: Getters<Product> = {
getId: () => p.id,
getName: () => p.name,
getPrice: () => p.price,
getInternalNotes: () => p.internalNotes,
};
const publicView: WithoutInternal<Product> = { id: p.id, name: p.name, price: p.price };
const numbers: OnlyNumbers<Product> = { id: 1, price: 1299 };
console.log(getters.getName(), publicView, numbers);Output
Kettle { id: 1, name: 'Kettle', price: 1299 } { id: 1, price: 1299 }Wrong Remapped Key
Example
The generated getter is getName, not getname (TS2561).
type Getters<T> = { [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K] };
const g: Getters<{ name: string }> = { getname: () => "x" };Compiler output (tsc)
Line 2: error TS2561: Object literal may only specify known properties, but 'getname' does not exist in type 'Getters<{ name: string; }>'. Did you mean to write 'getName'?