Hint
for...in at the type level — iterate over keyof T and transform each property
Mapped types iterate over the keys of a type and apply a transformation to each property. They power all the modifier utility types.
// Partial implementation — adds ? to every property
type MyPartial<T> = {
[K in keyof T]?: T[K];
// for each key K in T, make it optional
};
// Required implementation — removes ? from every property
type MyRequired<T> = {
[K in keyof T]-?: T[K];
// -? removes optionality
};
// Readonly implementation — adds readonly to every property
type MyReadonly<T> = {
readonly [K in keyof T]: T[K];
};
// Mutable (remove readonly)
type Mutable<T> = {
-readonly [K in keyof T]: T[K];
};
// Record implementation
type MyRecord<K extends string | number | symbol, V> = {
[P in K]: V;
};
Remapping keys with as:
// Add getter prefix to all keys
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};
type UserGetters = Getters<{ name: string; age: number }>;
// { getName: () => string; getAge: () => number }
// Filter keys by type
type OnlyStrings<T> = {
[K in keyof T as T[K] extends string ? K : never]: T[K];
};
+? (add optional), -? (remove optional), +readonly, -readonly give you surgical control. -? is what Required uses to make every field mandatory.