Typescript: Der Zugriff auf Eigenschaften in Union von Objekttypen schlägt für Eigenschaften fehl, die nicht für alle Union-Mitglieder definiert sind

Erstellt am 10. Dez. 2016  ·  12Kommentare  ·  Quelle: microsoft/TypeScript

TypeScript-Version: 2.1.1

Code

type A = { a: string; } 
type B = { b: string; }
type AorB = A | B;

declare const AorB: AorB;

if (AorB.a) {
    // use AorB.a
}

Erwartetes Verhalten:
Der Code wird fehlerfrei kompiliert. Obwohl a nicht (notwendigerweise) für alle Mitglieder der Gewerkschaft existiert, sollte die Tatsache, dass es für einige existiert, es mir ermöglichen, nach .a und es zu verwenden, wenn es vorhanden ist.

Tatsächliches Verhalten:
Typoskript beschwert sich: "Eigenschaft a existiert nicht für Typ AorB ... Eigenschaft a existiert nicht für Typ B."

Question

Hilfreichster Kommentar

Ich finde eine Lösung im Buch:

interface A { x:  number;} 
interface B { y:  string;}
function doStuff ( q: A | B ) {
  if ( 'x'  in q) {
    //  if type A...
  }
  else {
    // if type B...
  }
}

Auszug aus: Basarat Ali Syed. "TypeScript Deep Dive." Apple Bücher.

Eine Eigenschaft für ein Objekt, die als Typschutz verwendet werden kann, und das TypeScript kann erkennen, welchen Typ Sie verwendet haben.

Alle 12 Kommentare

Der Arzt sagt:

Damit derselbe Code funktioniert, müssen Sie eine Typzusicherung verwenden:

let pet = getSmallPet();

if ((<Fish>pet).swim) {
    (<Fish>pet).swim();
}
else {
    (<Bird>pet).fly();
}

http://www.typescriptlang.org/docs/handbook/advanced-types.html

Dann in Ihrer Probe:

if ((<A>AorB).a) {
    // use AorB.a
}

Das Problem hierbei ist, dass B keine a -Eigenschaft deklariert und zur Laufzeit möglicherweise eine a -Eigenschaft eines beliebigen Typs aufweist (da Sie eine zuweisen können Objekt mit einem beliebigen Satz von Eigenschaften zu einem B , solange es eine b -Eigenschaft vom Typ string hat). Sie können dafür sorgen, dass eine a: undefined -Eigenschaft explizit in B deklariert wird (wodurch sichergestellt wird, dass B keine zufällige a -Eigenschaft hat):

type A = { a: string; } 
type B = { b: string; a: undefined }
type AorB = A | B;

declare const AorB: AorB;

if (AorB.a) {
    // Ok
}

Macht perfekt Sinn. Gehirnfurz.

Wenn Sie a: undefined für Typ B definieren, müssen Sie es beim Erstellen / Übergeben einer Variablen auf undefined .
Um dies zu umgehen, können Sie a als a?: undefined deklarieren, und Typoskript freut sich, wenn Sie es weglassen.

Wenn ich die Kommentare richtig verstehe, sollte dies funktionieren (aber wirft; auf dem Spielplatz getestet): Ist das ein Fehler oder nicht? 🤔

type LinkProps = {
    to: string;
    onClick?: undefined;
    // Link specific props:
    target: string;
}

type ButtonProps = {
    to?: undefined;
    onClick: Function;
    // Button specific props:
    disabled: boolean;
}

type ActionProps = LinkProps | ButtonProps;

const Action = (props: ActionProps) =>
    props.to ?
        'Link with target: ' + props.target // Error not on ButtonProps
    :
        'Button with disabled: ' + props.disabled; // Error: not on LinkProps

Action({
  to: 'dssd',
  target: '_blank'
});

Ich verstehe das überhaupt nicht. Ist if ((<A>AorB).a) dasselbe wie if (A.a) weil Sie es zurückzwingen, A einzugeben?

Wenn Sie a: undefined für Typ B definieren, müssen Sie es beim Erstellen / Übergeben einer Variablen auf undefined .
Um dies zu umgehen, können Sie a als a?: undefined deklarieren, und Typoskript freut sich, wenn Sie es weglassen.

Vielleicht ist es besser a?: never , jetzt können Sie nicht versehentlich undefined zuweisen

Was ist, wenn Sie nicht jedem Gewerkschaftsmitglied einen Namen geben? (Ich kann keine Typzusicherung wie oben ohne einen Namen für den bestätigten Typ vornehmen, oder?)

type u = "str" | {prop:"val"};
function f(arg:u){return arg.prop} // TypeScript: Property 'prop' does not exist on type 'u'

Irgendeine Lösung?

Ich finde eine Lösung im Buch:

interface A { x:  number;} 
interface B { y:  string;}
function doStuff ( q: A | B ) {
  if ( 'x'  in q) {
    //  if type A...
  }
  else {
    // if type B...
  }
}

Auszug aus: Basarat Ali Syed. "TypeScript Deep Dive." Apple Bücher.

Eine Eigenschaft für ein Objekt, die als Typschutz verwendet werden kann, und das TypeScript kann erkennen, welchen Typ Sie verwendet haben.

type ColorItemType = {
    colorId: number,
    colorName: string,
}

type NumItemType = {
    numId: number,
    numName: string
}

type ResType = {
    itemId: number,
    // 0 color 1 num
    type: number,
    itemInfo: {
        colorList: Array<ColorItemType>
        numList: Array<NumItemType>
    }
}

const request = () => {
    return [{
        itemId: 1,
        type: 0,
        itemInfo: {
            colorList: [{
                colorId: 1,
                colorName: 'blue'
            }],
            numList: []
        }
    }];
};

const dataSource: Array<ResType> = request();

const formatData = dataSource.map(dataItem => {
    const list: Array<ColorItemType | NumItemType> = dataItem.type === 1 ? dataItem.itemInfo.numList : dataItem.itemInfo.colorList;
    return list.map(listItem => {
        return {
            // An error will be reported here
            value: listItem.numId || listItem.colorId,
            label: listItem.numName || listItem.colorName
        };
    });
});

Das Problem hierbei ist, dass B keine a -Eigenschaft deklariert und zur Laufzeit möglicherweise eine a -Eigenschaft eines beliebigen Typs aufweist (da Sie eine zuweisen können Objekt mit einem beliebigen Satz von Eigenschaften zu einem B , solange es eine b -Eigenschaft vom Typ string hat). Sie können dafür sorgen, dass eine a: undefined -Eigenschaft explizit in B deklariert wird (wodurch sichergestellt wird, dass B keine zufällige a -Eigenschaft hat):

type A = { a: string; } 
type B = { b: string; a: undefined }
type AorB = A | B;

declare const AorB: AorB;

if (AorB.a) {
    // Ok
}

Funktioniert bei mir nicht 07.10.2020

Und ich denke, dass dieses Verhalten von TS nicht gut ist, weil es einem Entwickler nicht viel hilft ...

War diese Seite hilfreich?
5 / 5 - 1 Bewertungen