Zoeken op website

Typescript type string is niet toewijsbaar aan type keyof wanneer ik waarde uit object haal


Kan iemand uitleggen waarom TypeScript in de onderstaande voorbeeldcode de foutmelding geeft "const key: string Argument of type 'string' is not assignable to parameter of type 'keyof Condition'"

interface Condition {
    GOOD: 'GOOD';
    BAD: 'BAD';
    NONE: 'NONE';
}

const ObjWithAllCondition: Condition = {
    GOOD: 'GOOD',
    BAD: 'BAD',
    NONE: 'NONE',
};

interface Result {
    condition: keyof Condition;
    count: number;
}

const getKeyValue = <T extends Condition, K extends keyof T>(obj: T, key: K) => obj[key];

const getResult = (): Result[] => {
    const result = [];
    for (const key in ObjWithAllCondition) {
        result.push({
            condition: getKeyValue(ObjWithAllCondition, key), // this is error
            count: 1,
        });
    }

    return result;
};

Antwoord #1

Omdat TypeScript een structureel typesysteem gebruikt, kunnen alle objecten extra eigenschappen hebben naast wat er in hun gedefinieerde type bestaat (en de compiler vindt dit prima zolang de eigenschappen die bekend zijn toewijsbaar zijn aan het type van het object).

Hierdoor kan het gebruik van de in-operator of methoden die over de sleutels van een object itereren, waarden teruggeven die niet van het type zijn dat u verwacht, dus al die sleutels/eigenschappen zijn van het type string (voor typeveiligheid).

Je kunt je voorbeeld refactoren om de eigenschappen in je Condition-type af te leiden van een array van de mogelijke sleutels, en die array vervolgens gebruiken bij het itereren over de sleutels. Hier is een voorbeeld:

TS-speelplaats

const conditions = ['GOOD', 'BAD', 'NONE'] as const;
type ConditionName = typeof conditions[number];

type StringUnionToKV<S extends string> = { [K in S]: K };

type Condition = StringUnionToKV<ConditionName>;

const obj: Condition = {
  GOOD: 'GOOD',
  BAD: 'BAD',
  NONE: 'NONE',
};

type Result = {
  condition: ConditionName;
  count: number;
};

const getKeyValue = <T extends Condition, K extends keyof T>(obj: T, key: K) => obj[key];

const getResult = (): Result[] => {
  const result = [];

  for (const key of conditions) {
    result.push({
      condition: getKeyValue(obj, key),
      count: 1,
    });
  }

  return result;
};

Als je met een vaste set strings gaat werken, ben je misschien ook geïnteresseerd in string-enums.

Gerelateerde artikelen