Mapped Types and Generics
The code explains itself: you define an interface without committing to concrete types in some utilities; when used, it should follow the original type constraints.
// Video for this file:
// https://youtu.be/oGczYPNAs1k
export interface Cat {
age: number;
name: string;
eat(): void;
}
// Readonly mapped type
type ReadonlyCat = {
readonly [P in keyof Cat]: Cat[P];
}
// Generic readonly
type GenericReadonly<T> = {
readonly [P in keyof T]: T[P];
}
type ReadonlyCat2 = GenericReadonly<Cat>;
// Make fields optional
type GenericPartial<T> = {
[P in keyof T]?: T[P];
}
type PartialCat = GenericPartial<Cat>;
type ReadonlyPartialCat = GenericReadonly<PartialCat>;
// Add nullability
type GenericNullable<T> = {
[P in keyof T]: T[P] | null;
}
type NullableCat = GenericNullable<Cat>;
// Proxy interface
interface Proxy<T> {
get(): T;
set(value: T): void;
}
// Reuse an interface; now each T key has a proxied getter/setter
type Proxied<T> = {
[P in keyof T]: Proxy<T[P]>;
}
type ProxiedCat = Proxied<Cat>;
const cat: ProxiedCat = null as any;
cat.age.get();
// Built-in helpers
type A = Readonly<Cat>;
type B = Partial<Cat>;
type C = Pick<Cat, 'age' | 'eat'>;
Reference video: https://youtu.be/oGczYPNAs1k