670 Stimmen

Schnittstellentypprüfung mit Typescript

Diese Frage ist das direkte Analogon zu Klassentypprüfung mit TypeScript

Ich muss zur Laufzeit herausfinden, ob eine Variable vom Typ any eine Schnittstelle implementiert. Hier ist mein Code:

interface A{
    member:string;
}

var a:any={member:"foobar"};

if(a instanceof A) alert(a.member);

Wenn Sie diesen Code in den Typescript-Spielplatz eingeben, wird die letzte Zeile als Fehler markiert: "Der Name A existiert nicht im aktuellen Bereich". Aber das ist nicht wahr, der Name existiert im aktuellen Bereich. Ich kann sogar die Variablendeklaration ändern in var a:A={member:"foobar"}; ohne Beanstandungen seitens des Herausgebers. Nachdem ich das Web durchsucht und die andere Frage zu SO gefunden hatte, änderte ich die Schnittstelle in eine Klasse, aber dann kann ich keine Objektliterale verwenden, um Instanzen zu erstellen.

Ich fragte mich, wie der Typ A auf diese Weise verschwinden konnte, aber ein Blick auf das generierte Javascript erklärt das Problem:

var a = {
    member: "foobar"
};
if(a instanceof A) {
    alert(a.member);
}

Es gibt keine Repräsentation von A als Schnittstelle, daher sind keine Laufzeittypprüfungen möglich.

Ich verstehe, dass Javascript als dynamische Sprache kein Konzept von Schnittstellen hat. Gibt es eine Möglichkeit, Typprüfung für Schnittstellen?

Die Autovervollständigung des typescript-Spielplatzes zeigt, dass typescript sogar eine Methode anbietet implements . Wie kann ich es verwenden?

11voto

Daniel Ribeiro Punkte 10026

Ich möchte darauf hinweisen, dass TypeScript keinen direkten Mechanismus zum dynamischen Testen bietet, ob ein Objekt eine bestimmte Schnittstelle implementiert.

Stattdessen kann TypeScript-Code die JavaScript-Technik verwenden, um zu prüfen, ob ein geeigneter Satz von Mitgliedern im Objekt vorhanden ist. Zum Beispiel:

var obj : any = new Foo();

if (obj.someInterfaceMethod) {
    ...
}

7voto

aledpardo Punkte 735

Basierend auf Fenton's responder Hier ist meine Implementierung einer Funktion, die prüft, ob eine gegebene object hat die Tasten und interface hat, sowohl ganz als auch teilweise.

Je nach Anwendungsfall müssen Sie möglicherweise auch die Typen der einzelnen Eigenschaften der Schnittstelle überprüfen. Der folgende Code tut das nicht.

function implementsTKeys<T>(obj: any, keys: (keyof T)[]): obj is T {
    if (!obj || !Array.isArray(keys)) {
        return false;
    }

    const implementKeys = keys.reduce((impl, key) => impl && key in obj, true);

    return implementKeys;
}

Beispiel für die Verwendung:

interface A {
    propOfA: string;
    methodOfA: Function;
}

let objectA: any = { propOfA: '' };

// Check if objectA partially implements A
let implementsA = implementsTKeys<A>(objectA, ['propOfA']);

console.log(implementsA); // true

objectA.methodOfA = () => true;

// Check if objectA fully implements A
implementsA = implementsTKeys<A>(objectA, ['propOfA', 'methodOfA']);

console.log(implementsA); // true

objectA = {};

// Check again if objectA fully implements A
implementsA = implementsTKeys<A>(objectA, ['propOfA', 'methodOfA']);

console.log(implementsA); // false, as objectA now is an empty object

7voto

Dmitry Matveev Punkte 5022

TypeGuards

interface MyInterfaced {
    x: number
}

function isMyInterfaced(arg: any): arg is MyInterfaced {
    return arg.x !== undefined;
}

if (isMyInterfaced(obj)) {
    (obj as MyInterfaced ).x;
}

6voto

xinthose Punkte 2462

Ich habe ein Beispiel aus @progress/kendo-data-query im Ordner filter-descriptor.interface.d.ts

Checker

declare const isCompositeFilterDescriptor: (source: FilterDescriptor | CompositeFilterDescriptor) => source is CompositeFilterDescriptor;

Beispiel für die Verwendung

const filters: Array<FilterDescriptor | CompositeFilterDescriptor> = filter.filters;

filters.forEach((element: FilterDescriptor | CompositeFilterDescriptor) => {
    if (isCompositeFilterDescriptor(element)) {
        // element type is CompositeFilterDescriptor
    } else {
        // element type is FilterDescriptor
    }
});

4voto

edbentley Punkte 181

Sie können einen TypeScript-Typ zur Laufzeit validieren, indem Sie ts-validate-type (dafür ist allerdings ein Babel-Plugin erforderlich):

const user = validateType<{ name: string }>(data);

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X