Home > Net >  Class property becomes a union instead of being discriminated by Generic Type
Class property becomes a union instead of being discriminated by Generic Type

Time:06-01

I'm trying to define property type based on generic type.

    interface Option<T> {
        text: string
        value: T
    }
    
    class MultiSelect<T, TGroup extends boolean = false> {
        public groups: TGroup;
        public options: TGroup extends true ? { group: Option<T> } : Option<T>
    
        constructor(groups: TGroup, options: TGroup extends true ? { group: Option<T> } : Option<T>) {
            this.groups = groups
            this.options = options
        }
    
        public get allOptions(): Option<T> {
            return this.groups ? this.options.group : this.options
        }
    }

But this.options is not being discriminated by TGroup and instead becomes a union Option<T> | { group: Option<T>; }

Therefore when trying to access this.optoin.group from within ternary it errors

Property 'group' does not exist on type 'Option<T> | { group: Option<T>; }'.
  Property 'group' does not exist on type 'Option<T>'

Here is Typescript Playground

CodePudding user response:

Typescript type discrimination requires that the types that you want to discriminate between be defined in a union. You can have TS discriminate here if you combine the groups and options properties into a single type and then create a union of the two variations.

interface Option<T> {
    text: string
    value: T
}

type SelectOptions<T> = {
    groups: false
    options: Option<T>
} | {
    groups: true
    options: {
        group: Option<T>
    }
}

class MultiSelect<T> {
    private selectOptions: SelectOptions<T>

    constructor(selectOptions: SelectOptions<T>) {
        this.selectOptions = selectOptions
    }

    public get allOptions(): Option<T> {
        return this.selectOptions.groups ? this.selectOptions.options.group : this.selectOptions.options
    }
}

Typescript Playground

  • Related