I use simple-schema to define DB schemas in an object:
{ name: 'string', age: 'integer', ... }
Is it somehow possible to create an interface or class from this object, so I don’t have to type everything twice?
Advertisement
Answer
You can do this, but it might be more trouble than it’s worth unless you think you might be changing the schema. TypeScript doesn’t have built-in ways of inferring types in a way that you want, so you have to coax and cajole it to do so:
First, define a way of mapping the literal names 'string'
and 'integer'
to the TypeScript types they represent (presumably string
and number
respectively):
type MapSchemaTypes = { string: string; integer: number; // others? } type MapSchema<T extends Record<string, keyof MapSchemaTypes>> = { -readonly [K in keyof T]: MapSchemaTypes[T[K]] }
Now if you can take an appropriately typed schema object like the one you specified, and get the associated type from it:
const personSchema = {name: 'string', age: 'integer'}; type Person = MapSchema<typeof personSchema>; // ERROR
Oops, the problem is that personSchema
is being inferred as {name: string; age: string}
instead of the desired {name: 'string'; age: 'integer'}
. You can fix that with a type annotation:
const personSchema: { name: 'string', age: 'integer' } = { name: 'string', age: 'integer' }; type Person = MapSchema<typeof personSchema>; // {name: string; age: number};
But now it feels like you’re repeating yourself. Luckily there is a way to force it to infer the proper type:
function asSchema<T extends Record<string, keyof MapSchemaTypes>>(t: T): T { return t; } const personSchema = asSchema({ name: 'string', age: 'integer' }); // right type now type Person = MapSchema<typeof personSchema>; // {name: string; age: number};
UPDATE 2020-06: in more recent TS versions you can use a const
assertion to get the same result:
const personSchema = { name: 'string', age: 'integer' } as const; type Person = MapSchema<typeof personSchema>;
That works!
See it in action on the Typescript Playground. Hope that helps; good luck!