You can drop the following code into a foo.ts file. I am trying to dynamically generate types. What I am doing is based off this question: Map array to an interface
type TypeMapping = {
Boolean: boolean,
String: string,
Number: number,
ArrayOfString: Array<string>,
}
export enum Type {
Boolean = 'Boolean',
String = 'String',
Number = 'Number',
ArrayOfString = 'ArrayOfString'
}
const asOptions = <K extends Array<string>, T extends Array<{ name: K, type: keyof TypeMapping }>>(t: T) => t;
type OptionsToType<T extends Array<{ name: Array<string>, type: keyof TypeMapping }>>
= { [K in T[number]['name'][0]]: TypeMapping[Extract<T[number], { name: K }>['type']] }
const options = asOptions([
{
name: ['foo'],
type: Type.Boolean
},
{
name: ['bar'],
type: Type.String
},
{
name: ['baz'],
type: Type.Number
},
{
name: ['bab'],
type: Type.ArrayOfString
}
]);
export type Opts = OptionsToType<typeof options>;
const v = <Opts>{foo: true}; // this does not compile
console.log(typeof v.foo);
I don't get any type completion - when I type v.
nothing shows up.
Here is an example that uses Typescript 3, and an object as the input. I do something very similar to this in my own projects to generate a typed query builder wrapper for knex.js from my Postgres database.
Here is a way to use your current interface:
Assuming you are using the first element of the
name
property as the actual key to add to the resultant type, your definitions are a little off. I would fix them to be:The differences:
I am still using
K extends string
to induce inference of a string literal inasOptions
. There are places where TypeScript infers string literals and other places where it infers juststring
, andK extends Array<string>
will not infer a string literal. SoK
is still a string type, and instead I've made thename
property as{0: K}
which will ensure that it inspects the first element of the array.Again in
OptionsToType
,K
is a string literal, so you must extract the piece ofT['number']
that hasK
as the first element of thename
property, which isExtract<T[number], {name: {0: K} }>
.The rest should work now, I think. Hope that helps. Good luck.