Skip to content

Instantly share code, notes, and snippets.

@sgoguen
Last active February 24, 2021 16:19
Show Gist options
  • Save sgoguen/abfb62e2571dc8ca4ca30be84475e04c to your computer and use it in GitHub Desktop.
Save sgoguen/abfb62e2571dc8ca4ca30be84475e04c to your computer and use it in GitHub Desktop.
Using TypeScript's Mapped Types and Index Types to extract message types from an interface
// Given an interface like this, I can have TypeScript automatically
// generate message types from all of the "update" methods below.
export interface Person {
// We'll ignore these properties
name: string;
age: number;
dob: Date;
// We'll ignore any method that returns void (We want methods to return new methods)
setDate(newDate: Date): void;
// Methods accepting simple types are ok
setName(newName: string): Person;
setAge(newAge: number): Person;
// But we'll ignore methods with more than one argument for now
setBoth(newName: string, newAge: number): Person;
// A method accepting a record is good
setBothObj(r: { newName: string, newAge: number }): Person;
}
/*
Given our Person type, we want to extract a union type.
type PersonUpdateMessage = {
type: "setName";
payload: string;
} | {
type: "setBothObj";
payload: {
newName: string;
newAge: number;
};
} | {
type: "setAge";
payload: number;
}
*/
// We'll use mapped types to extract the key name and payload type.
// Then we'll use index types at the end to create our union type.
export type UpdateMessages<T> = {
[K in keyof T]: T[K] extends ((x: infer P) => T) ? { type: K, payload: P } : never
}[keyof T];
// Intellisense shows your new update message types
export type PersonUpdateMessage = UpdateMessages<Person>;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment