Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
// Firstly define the entities
type DataSchema = {
client: {
dto: { id: string, name: string},
entity: {clientId: string, clientName: string}
},
order: {
dto: { id: string, amount: number},
entity: {orderId: string, quantity: number}
},
}
// transvers to lookup the property type
type PropertyType<T, Path extends string> = Path extends keyof T ? T[Path] : never;
type lookup<T, Key extends keyof T, prop extends string> = PropertyType<T[Key], prop>;
// one liner version
type lookup2<T, Key extends keyof T, prop extends string> = prop extends keyof T[Key] ? T[Key][prop] : never;
// mapTo and MapFrom
type MapTo<T extends string> = `to${Capitalize<T>}`;
type MapFrom<T extends string> = `from${Capitalize<T>}`;
type ExtractMapperTo<Type> = {
[Key in keyof Type as MapTo<Key extends string ? Key : never>]: (args: lookup<Type, Key, 'dto'>) => lookup<Type, Key, 'entity'>;
};
type ExtractMapperFrom<Type> = {
[Key in keyof Type as MapFrom<Key extends string ? Key : never>]:(args: lookup<Type, Key, 'entity'>) => lookup<Type, Key, 'dto'>;
};
// Then all these mapper methods are automatically created
type mapper = ExtractMapperTo<DataSchema> & ExtractMapperFrom<DataSchema>;
// Our first goal achieved!
declare const m: mapper;
m.toClient({id: '123', name: 'John'});
m.fromClient({clientId: '123', clientName: 'John'});
m.toOrder({id: '123', amount: 3});
m.fromOrder({orderId: '345',quantity: 4});
// Derive the data type names into a union type
type PropToUnion<T> = {[k in keyof T]: k}[keyof T];
type DataTypes = PropToUnion<DataSchema>;
// Second goal achieved
function getProcessName(c: DataTypes): string {
switch(c) {
case 'client':
return 'register' + c;
case 'order':
return 'process' + c;
default:
return assertUnreachable(c);
}
}
function assertUnreachable(x: never): never {
throw new Error("something is very wrong");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment