javascript - Hvordan implementere et grensesnitt med betingede typer i TypeScript


I et personlig prosjekt står jeg overfor et problem med TypeScript betingede typer. Jeg har grunnleggende forståelse av betingede typer fra TypeScript-dokumentasjonen. Jeg ville forventet at oppsettet nedenfor skulle fungere, men det gir en typefeil.

I utgangspunktet prøver jeg å definere et grensesnitt for en tre-node som lastes fra disken. Dette betyr at noen av nodene kanskje ikke lastes riktig på grunn av manglende filer osv. Så enhver node-implementering inneholder enten Content eller Error.

interface Content {
  data: number;
}

interface Error {
  code: string;
}

export interface TreeNode<T extends Content | Error> {
  getValue(): T extends Content ? number : string;
}

class ValueNode<ValueType extends Content> implements TreeNode<ValueType> {
  private readonly value: number;
  public constructor(value: number) {
    this.value = value;
  }
 
  public getValue(): number {
    return this.value;
  }
}

Jeg ville forventet at implementeringen av getValue-metoden ville være tillatt å returnere string siden grensesnittet er implementert med type som utvider Content. Men jeg får denne typefeilen i stedet:

  • Egenskapen getValue i typen ValueNode<ValueType> kan ikke tilordnes til samme egenskap i basistypen TreeNode<ValueType>.

    • Type () => number kan ikke tildeles til type () => ValueType extends Content ? number : string.

      • Type number kan ikke tildeles type ValueType extends Content ? number : string
      • Type () => number kan ikke tilordnes til type () => ValueType extends Content ? number : string.
      • Type number kan ikke tilordnes til type ValueType extends Content ? number : string

Klart, jeg gjør det på feil måte. Hva ville være den riktige måten å oppnå målet mitt på?

Svar #1

Som @Dai påpekte, er det bedre å ikke overskygge den innebygde Error-typen (slik at du kan bruke den i modulen din).

Her er to alternativer:

TS-lekeplasslenke

interface ContentValue {
  data: number;
}

interface ErrorValue {
  code: string;
}

export interface ValueGetter<T> {
  getValue(): T;
}

class ValueNode<T extends ContentValue> implements ValueGetter<ContentValue['data']> {
  public constructor(private readonly value: T) {}
 
  public getValue(): number {
    return this.value.data;
  }
}

// or
class SimpleValueNode<T extends ContentValue> {
  public constructor(private readonly value: T) {}
 
  public getValue(): number {
    return this.value.data;
  }
}

Relaterte artikler