Annotated solution
Published August 20, 2026The solution
type Getters<T> = { [K in keyof T as `get${Capitalize<K & string>}`]: () => T[K] }
The common wrong answer
type Getters<T> = { [K in keyof T as `get${K & string}`]: () => T[K] }
Everything is right except the case: this produces `getname` and `getage`. Concatenation alone does not capitalise, and in camelCase method names that single character is the whole convention.
Line by line
K & string`keyof T` can include `symbol` and `number`, neither of which `Capitalize` accepts. Intersecting with `string` narrows the key to the part that can be interpolated, and silently drops the rest.
() => T[K]The value becomes a function type while the key is being rewritten. Both halves of the property change in the same mapping, which is why this needs no second pass.
Takeaway
Key remapping composes with everything else in the type system: template literals, the intrinsic case types, and conditionals all work inside an `as` clause. This is how ORMs and event-emitter types generate their APIs.

