Website-Suche

Typescript-Funktion akzeptiert falsches Argument ohne Fehler


Fall 1: Keine Fehler festgestellt, wenn "randomKey" an doMethod übergeben wird.

interface Options {
 bar: string;
 foo?: number;
}

function doMethod(options: Options) {
 console.log(options);
}


const options = {
 bar: 'bar',
 foo: 123,
 randomKey: 231,
}
doMethod(options); // No errors appear!
console.log(options);

Fall 2: Fehler treten nur auf, wenn Optionen direkt an die Funktion übergeben werden

interface Options {
 bar: string;
 foo?: number;
}

function doMethod(options: Options) {
 console.log(options);
}

doMethod({
 bar: 'bar',
 foo: 123,
 randomKey: 231, // ERROR: "Object literal may only specify known properties, and 'randomKey' does not exist in type 'Options'."
});

console.log(options); // In this scenario, I cannot console log options

Der stille Fehler ist schwer zu finden. Zum Beispiel kann man leicht ein Wort falsch schreiben, und Dinge könnten nicht so passieren, wie man es möchte.

Was passiert, wenn man „foo“ falsch schreibt, zum Beispiel „fooo“? Der stille Fehler würde trotzdem auftreten. Man erwartet, dass „foo“ etwas auslöst, aber in diesem Fall würde es nicht ausgelöst werden, wenn man „fooo“ schrieb.

Antwort #1

TypeScript bietet ein Konzept der Frische (auch als strikte Überprüfung von Objektliteralen bezeichnet), um es einfacher zu machen, Objektliterale zu typprüfen, die sonst strukturell typkompatibel wären.

-- Quelle TypeScript Deep Dive

Folgen Sie dem obigen Link, er erklärt dieses Thema ziemlich klar.

Hier werde ich kurz mit Ihrem Szenario erklären.

// case 1: no error
const options = { bar: 'bar', foo: 123, randomKey: 231 };
doMethod(options);

// case 2: error
doMethod({ bar: 'bar', foo: 123, randomKey: 231 });

In der Laufzeit von JavaScript sollte in beiden Anwendungsfällen alles einfach funktionieren. Das ist wahr, weil JS schwach typisiert ist, zusätzliche Schlüssel in einem Objekt verursachen zur Laufzeit keinen Schaden.

Zurück zu TS: Sie geben an, dass doMethod(options) Optionen akzeptieren soll, die die Form { bar: string; foo?: number } haben. Dies gibt Ihre Mindestanforderung für die Eingabe zu doMethod an. Eingaben mit zusätzlichen Schlüsseln? Kein Problem, so funktioniert JS.

Warum sollte TS dir in Fall 2 überhaupt einen Fehler anzeigen?

Weil TS möchte, dass du weißt, dass der zusätzliche randomKey unnötig ist! Auch wenn er keinen Schaden anrichtet.

Das ist die Idee hinter dem Frischekonzept. Ein Analog wäre wie:

function add(a: number, b: number) { return a + b };

add(1, 2, 3); // TS Error

Auch wenn diese Verwendung in der JS-Laufzeit noch funktioniert, meinst du das wahrscheinlich nicht. Deshalb warnt dich TS im Voraus davor.

Um den zweiten Teil Ihrer Frage zu beantworten, was ist, wenn Sie nur die Frische eines Objekts bewahren möchten, was ist, wenn Sie die genaue Form der Eingabe streng überprüfen lassen möchten? Es gibt eine Lösung mit Nachteil:

type ExactShape<T, R> = T extends R
  ? Required<R> extends T
    ? T
    : never
  : never

function doMethod<T>(options: ExactShape<T, Options>) {
   console.log(options);
}

TypeScript Playground Live-Demo

Dieses Mal wird TS einen Fehler auswerfen, wie du es wünschst. Aber der Nachteil ist, dass beim Überfahren des Fehlers mit der Maus keine nützlichen Informationen mehr angezeigt werden, warum du falsch liegst.

Antwort #2

Es gibt kein Problem. Es ist normales Verhalten. Betrachten Sie die Schnittstelle als Versprechen, die Daten bereitzustellen.

Es ist wichtig zu bedenken, dass TypeScript am Ende des Tages in Vanille-JavaScript kompiliert wird.

Solange Sie alle Daten für die Schnittstelle bereitstellen, spielt es keine Rolle, ob das tatsächliche Objekt, das Sie bereitstellen, zusätzliche Informationen enthält.

Gutes Beispiel ist

interface Options {
 bar: string;
 foo?: number;
 randomKey: number
}

const doMethod =(options: Options): any=> {
 console.log(options);
}


const options = {
 bar: 'bar',
 foo: 123
}
doMethod(options); ** error appears!**
console.log(options);

Um eine bessere typensichere Erfahrung zu erhalten, möchten Sie möglicherweise auch ein Interface für das Objekt verwenden.

const options: Options = { bar: 'bar', foo: 123 } 

Auf diese Weise werden Sie gezwungen, die Schnittstelle einzuhalten, und erhalten einen Fehler, falls Sie versuchen, unerwartete zusätzliche Daten hinzuzufügen.

Verwandte Artikel