Reputation: 545
I am looking to get type inference based on the value of keys in an array.
For context, I'm working on a class where you can pass in a list of options and a default value:
interface Option {
value: string;
}
interface SelectArgs {
options: Option[];
defaultValue: Option['value'];
}
class SelectConfig {
options: Option[];
defaultValue: Option['value'] // can I get the value options with autocompletion here?
constructor(args: SelectArgs ) {
Object.assign(this, args);
}
}
I would be using this in the context of a class, so for example, if I instantiate a new class:
const select = new SelectOptions({
options: [{value: 'Hello'}, {value: 'World'}]
defaultValue: "Hello" // I want to give me type inference of either "Hello" | "World"
})
What is the best way to type defaultValue
in this case so it is always one of the passed in values
of options
?
Upvotes: 1
Views: 165
Reputation: 26326
Yes, it'll look something like this, using a generic parameter for the class:
type Narrow<T> =
| (T extends infer U ? U : never)
| Extract<T, number | string | boolean | bigint | symbol | null | undefined | []>
| ([T] extends [[]] ? [] : { [K in keyof T]: Narrow<T[K]> });
class SelectConfig<Options extends Option[]> {
options!: Options;
defaultValue!: Options[number]['value']
constructor(args: {
options: Narrow<Options>;
defaultValue: Options[number]["value"]
}) {
Object.assign(this, args);
}
}
I opted to use this Narrow
utility type so you don't need to use as const
when creating the class. We'll narrow the type of the given options, then set the type of the default value to any of the values given in the options.
Upvotes: 3