简体   繁体   中英

Destructuring fails on type depending on generic

I have these 2 interfaces:

export interface Converter<T> {
  decode?: Decoder<T>;
  encode?: Encoder<T>;
  notify?: Notifier<T>;
  type?: T;
}

export interface Api {
  state: Converter<State>;
  water: Converter<Water>;
  version: Converter<Versions>;
}

In this class I make use of these interfaces. Particularly, I have a function called write where I make sure the the parameter name is a key of the Api interface and the value is the corresponding Generic of that key.

export default class Characteristic {
  private api: Api;

  public async write<Name extends keyof Api, Value = Api[Name]["type"]>(
    name: Name,
    value: Value
  ): Promise<void> {
    const { encode } = this.api[name];
    const buffer = encode(value);
    //                    ^^^^^
  }
}

This pattern works as expected, but here I get an error on value that I don't quite understand:

 Type '"sleep" | "goingToSleep" | "idle" | "busy" | "espresso" | "steam" | "hotWater" | "shortCal" | "selfTest" | "longCal" | "descale" | "fatalError" | "init" | "noRequest" | "skipToNext" | ... 7 more ... | Versions' is not assignable to type 'Value'. '"sleep" | "goingToSleep" | "idle" | "busy" | "espresso" | "steam" | "hotWater" | "shortCal" | "selfTest" | "longCal" | "descale" | "fatalError" | "init" | "noRequest" | "skipToNext" | ... 7 more ... | Versions' is assignable to the constraint of type 'Value', but 'Value' could be instantiated with a different subtype of constraint '{}'. Type '"sleep"' is not assignable to type 'Value'. '"sleep"' is assignable to the constraint of type 'Value', but 'Value' could be instantiated with a different subtype of constraint '{}' 

I think Typescript is complaining about the lack of constraints on Value here. You give it a default value, but it could be still overridden to a different type.

Do you need to make the Value type generic there? You could change the method signature like this:

public async write<Name extends keyof Api>(
  name: Name,
  value: Api[Name]["type"]
): Promise<void> {

Optionally add a type helper to make it look neater:

type ValueFor<Name extends keyof Api> = Api[Name]["type"];

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM