这个问题直接类似于TypeScript中的类类型检查

我需要在运行时找出任何类型的变量是否实现了接口。这是我的代码:

interface A{
    member:string;
}

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

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

如果您在typescript游乐场中输入这段代码,最后一行将被标记为错误,“名称A不存在于当前作用域”。但事实并非如此,该名称确实存在于当前作用域中。我甚至可以更改变量声明为var a: a ={成员:"foobar"};没有编辑的抱怨。在浏览网页并找到其他问题后,我将接口更改为类,但我不能使用对象字面量来创建实例。

我想知道A类型是如何消失的,但看看生成的javascript就能解释这个问题:

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

没有将A表示为接口,因此不可能进行运行时类型检查。

我知道javascript作为一种动态语言没有接口的概念。是否有方法对接口进行类型检查?

typescript游乐场的自动完成显示typescript甚至提供了一个方法实现。我怎么使用它?


当前回答

用户定义类型保护呢?https://www.typescriptlang.org/docs/handbook/advanced-types.html

interface Bird {
    fly();
    layEggs();
}

interface Fish {
    swim();
    layEggs();
}

function isFish(pet: Fish | Bird): pet is Fish { //magic happens here
    return (<Fish>pet).swim !== undefined;
}

// Both calls to 'swim' and 'fly' are now okay.

if (isFish(pet)) {
    pet.swim();
}
else {
    pet.fly();
}

其他回答

export interface ConfSteps {
    group: string;
    key: string;
    steps: string[];
}
private verify(): void {
    const obj = `{
      "group": "group",
      "key": "key",
      "steps": [],
      "stepsPlus": []
    } `;
    if (this.implementsObject<ConfSteps>(obj, ['group', 'key', 'steps'])) {
      console.log(`Implements ConfSteps: ${obj}`);
    }
  }
private objProperties: Array<string> = [];

private implementsObject<T>(obj: any, keys: (keyof T)[]): boolean {
    JSON.parse(JSON.stringify(obj), (key, value) => {
      this.objProperties.push(key);
    });
    for (const key of keys) {
      if (!this.objProperties.includes(key.toString())) {
        return false;
      }
    }
    this.objProperties = null;
    return true;
  }

现在这是可能的,我刚刚发布了一个增强版的TypeScript编译器,它提供了完整的反射功能。您可以从类的元数据对象实例化类,从类构造函数检索元数据,并在运行时检查接口/类。你可以在这里查看

使用的例子:

在你的一个typescript文件中,创建一个接口和一个实现它的类,如下所示:

interface MyInterface {
    doSomething(what: string): number;
}

class MyClass implements MyInterface {
    counter = 0;

    doSomething(what: string): number {
        console.log('Doing ' + what);
        return this.counter++;
    }
}

现在让我们打印一些已实现接口的列表。

for (let classInterface of MyClass.getClass().implements) {
    console.log('Implemented interface: ' + classInterface.name)
}

使用reflect -ts编译并启动它:

$ node main.js
Implemented interface: MyInterface
Member name: counter - member kind: number
Member name: doSomething - member kind: function

有关接口元类型的详细信息,请参阅reflect .d.ts。

更新: 您可以在这里找到一个完整的工作示例

这里还有另一个选项:模块ts-interface-builder提供了一个构建时工具,可以将TypeScript接口转换为运行时描述符,ts-interface-checker可以检查对象是否满足它。

对于OP的例子,

interface A {
  member: string;
}

首先运行ts-interface-builder,它会生成一个带有描述符(比如foo-ti)的新简洁文件。Ts,你可以这样用:

import fooDesc from './foo-ti.ts';
import {createCheckers} from "ts-interface-checker";
const {A} = createCheckers(fooDesc);

A.check({member: "hello"});           // OK
A.check({member: 17});                // Fails with ".member is not a string" 

你可以创建一个单行类型保护函数:

function isA(value: any): value is A { return A.test(value); }

使用字符串文字是很困难的,因为如果你想重构你的方法或接口名称,那么你的IDE可能不重构这些字符串文字。 我为您提供我的解决方案,如果在接口中至少有一个方法

export class SomeObject implements interfaceA {
  public methodFromA() {}
}

export interface interfaceA {
  methodFromA();
}

检查object是否为interface类型:

const obj = new SomeObject();
const objAsAny = obj as any;
const objAsInterfaceA = objAsAny as interfaceA;
const isObjOfTypeInterfaceA = objAsInterfaceA.methodFromA != null;
console.log(isObjOfTypeInterfaceA)

注意:即使我们删除了'implements interfaceA',我们也会得到true,因为SomeObject类中仍然存在该方法

我想指出的是,TypeScript并没有提供直接的机制来动态测试一个对象是否实现了特定的接口。

相反,TypeScript代码可以使用JavaScript技术来检查对象上是否存在适当的成员集。例如:

var obj : any = new Foo();

if (obj.someInterfaceMethod) {
    ...
}