Reputation: 2359
Given the interface
interface FormField {
name: string;
}
and a value such as:
const fields: FormField[] = [
{ name: 'givenName' },
{ name: 'familyName' }
]
I would like to infer this interface:
interface FormModel {
givenName: string;
familyName: string;
}
So use the array's property values as property names.
I tried something like:
type Model<T extends Array<FormField>> = { [K['name'] in T]: string };
but this doesn't work. Is this kind of thing possible in Typescript?
Upvotes: 0
Views: 907
Reputation: 74820
Your solution already goes in the right direction, we can tune the types a bit up to make it work:
// make name generic, so we can refer to concrete string literal
interface FormField<T extends string> {
name: T;
}
const fields = [
{ name: 'givenName' },
{ name: 'familyName' }
] as const // const assertion to retain strings "givenName" and "familyName"
// T[number] gives all possible array values, T[number]["name"] all possible names
type Model<T extends ReadonlyArray<FormField<any>>> = { [K in T[number]["name"]]: string };
type FormModel = Model<typeof fields> // { givenName: string; familyName: string; }
fields
doesn't have an explicit type FormField[]
anymore in order to preserve literal types. If you still want to have stong type checks for fields
, you can use a factory function:
const formField = <T extends string>(t: T): FormField<T> => ({ name: t })
const fields = [
formField('givenName'),
formField('familyName'),
formField(3) // 💣, error
]
Upvotes: 1