2017-10-13 2 views
1

Ich habe alle strengen Flaggen, die ich auf erwarten gedreht würde, also war ich verwirrt, als Typoskript den folgenden Code akzeptiert:Verhindern Typoskript aus der Gewährung des undefinierten Rückkehr

export class Test { 
    private records: { 
     [id: string]: number 
    }; 
    constructor() { 
     this.records = { 
      "hello": 1, 
      "world": 3 
     } 
    } 

    public get(id: string): number { 
     return this.records[id]; 
    } 
} 

Die get Eigenschaft offensichtlich tut nicht immer eine Zahl zurückgeben: es wird undefined zurückgeben, wenn die Funktion alles außer "hello" und "world" übergeben wird. Gibt es ein Flag, das diese Funktion abfangen würde und seinen Rückgabetyp number | undefined erfordern würde, welcher der richtige Rückgabetyp ist?

Ich verwende bereits noImplicitAny und strictNullChecks. Sicherlich gibt es eine Möglichkeit, dies zu tun, da ich eine Funktion habe, die behauptet, eine number zurückgeben undefined zurückgeben!

+0

Ihr Typ sagt, dass * jeder * String-Schlüssel für dieses Objekt eine Zahl zurückgibt. Wenn nur bestimmte bekannte Eigenschaften verfügbar sein sollen, verwenden Sie einen spezifischeren Typ. – jonrsharpe

+0

@jonrsharpe - wenn das der Fall war, dann sollte es einen Typfehler im Konstruktor geben, und es gibt keinen. Ich bin mir bewusst, dass ich in dieser Instanz einen spezifischeren Schnittstellentyp verwenden könnte, aber das Beispiel, von dem ich das nahm, hatte eine Methode 'set (id: string, n: number): void'. –

+1

Grundsätzlich tritt das Problem auf, weil Ihr Typ für 'records' falsch ist. Wie du sagst, wenn der Schlüssel fehlt, wirst du undefiniert, also sollte es '[id: string]: number | sein undefiniert. Dann erhalten Sie die entsprechenden Warnungen zu der Methode. Ich weiß nicht, warum du denkst, dass es im Konstruktor einen Typfehler geben sollte. Siehe auch dieses Problem: https://github.com/Microsoft/TypeScript/issues/9235 – jonrsharpe

Antwort

0

Basierend auf jonrsharpe's Kommentare fand ich schließlich this thread. Die Antwort, wie ich es verstehe, ist, dass diese Art:

interface Wha { 
    foo: number; 
    bar: number; 
    [id: string]: number; 
}; 

ist immer falsch, da das Typsystem behandelt es wie es ein Objekt, das jeden einzelnen id zu einem Karten definierte Anzahl und kein solches Objekt kann jemals existieren. (Jedes Objekt, das Sie möglicherweise erstellen können, werden immer Strings haben, die Zahlen nicht zusammen, wie lilezek in Kommentaren darauf hingewiesen.)

Typoskript ist vollkommen zufrieden geben dieses Objekt den Wha Typ:

let r: Wha = { foo: 4, bar: 7, baz: 33 }; 

Weil es fälschlicherweise denkt, dass jeder string Index in einem Wha Objekt einem definierten number zugeordnet ist, behandelt Typescript r.notafield, r.fnord und r["ha"] als Typ number. Daher wird es glücklich gehen, als ob alle diese Dinge nicht möglicherweise undefined sein können. Aber sie sind alle undefined! diese Situation zu vermeiden, ist, warum ich mit --strictNullChecks in erster Linie

Wenn Sie möchten, zu vermeiden, dass eine Reihe von undefined Dinge zippen um die typechecker verwenden Typoskript wollte eine ganz definierte number zu sein vorgibt, ist die einzige Option, ist dies:

interface Wha { 
    foo: number; 
    bar: number; 
    [id: string]: number | undefined; 
}; 

Dies führt zu allen möglichen Problemen, weil es bedeutet, dass Sie gültige Schlüssel im Array haben kann, die zu undefinierten abgebildet, wo das, was Sie ursprünglich war gemeint, dass, wenn k in Object.keys(r) ein Schlüssel ist, dann ist r[k] ein number. Also, es gibt keine gute Option hier.

Vielleicht ist die Lektion hier, dass ich ES6 Maps anstelle von indexierbaren Typen verwenden sollte, weil indexierbare Typen Ihnen ohne Warnung liegen.

0

Versuchen mit diesem:

public get(id: string): number | undefined { 
    return this.records[id]; 
} 

Oder diese:

public get(id: string) { 
    return this.records[id] as number | undefined; 
} 

Eine davon explizit nicht definiert als eine mögliche Art zurückgeben sollte.

Verwandte Themen