DrummerGenius
DrummerGenius

Reputation: 545

Get type inference from keys in a dynamic array in TypeScript

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

Answers (1)

tenshi
tenshi

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.

Playground

Upvotes: 3

Related Questions