这个问题直接类似于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甚至提供了一个方法实现。我怎么使用它?


当前回答

你可以在没有instanceof关键字的情况下实现你想要的,因为你现在可以编写自定义类型保护:

interface A {
    member: string;
}

function instanceOfA(object: any): object is A {
    return 'member' in object;
}

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

if (instanceOfA(a)) {
    alert(a.member);
}

会员众多

如果需要检查大量成员以确定对象是否与您的类型匹配,则可以添加标识符。下面是最基本的示例,并要求您管理自己的鉴别器…您需要深入了解模式,以确保避免重复标识符。

interface A {
    discriminator: 'I-AM-A';
    member: string;
}

function instanceOfA(object: any): object is A {
    return object.discriminator === 'I-AM-A';
}

var a: any = {discriminator: 'I-AM-A', member: "foobar"};

if (instanceOfA(a)) {
    alert(a.member);
}

其他回答

用户定义类型保护呢?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();
}

我知道这个问题有点老了,但这只是我的五毛钱。这招对我很管用:

const container: Container = icc.controlComponent as unknown as Container;
if (container.getControlComponents) {
    this.allControlComponents.push(...container.getControlComponents());
}

容器是接口,而icc。controlComponent是我想检查的对象,getControlComponents是来自Container接口的一个方法。

Typescript 2.0引入了带标签的联合

Typescript 2.0特性

interface Square {
    kind: "square";
    size: number;
}

interface Rectangle {
    kind: "rectangle";
    width: number;
    height: number;
}

interface Circle {
    kind: "circle";
    radius: number;
}

type Shape = Square | Rectangle | Circle;

function area(s: Shape) {
    // In the following switch statement, the type of s is narrowed in each case clause
    // according to the value of the discriminant property, thus allowing the other properties
    // of that variant to be accessed without a type assertion.
    switch (s.kind) {
        case "square": return s.size * s.size;
        case "rectangle": return s.width * s.height;
        case "circle": return Math.PI * s.radius * s.radius;
    }
}

我知道我偶然发现了一个github包,它正确地解决了这个问题,在我的搜索历史中,我终于找到了它。检查typescript-is -尽管它要求你的代码使用ttypescript编译(我目前正在强迫它与create-react-app一起工作,稍后将在成功/失败时更新),你可以用它做各种疯狂的事情。与ts-validate-type不同,这个包也是主动维护的。

你可以检查某个东西是否是字符串或数字,并将其作为字符串或数字使用,而编译器不会抱怨:

import { is } from 'typescript-is';

const wildString: any = 'a string, but nobody knows at compile time, because it is cast to `any`';

if (is<string>(wildString)) { // returns true
    // wildString can be used as string!
} else {
    // never gets to this branch
}

if (is<number>(wildString)) { // returns false
    // never gets to this branch
} else {
    // Now you know that wildString is not a number!
}

你也可以检查你自己的接口:

import { is } from 'typescript-is';

interface MyInterface {
    someObject: string;
    without: string;
}

const foreignObject: any = { someObject: 'obtained from the wild', without: 'type safety' };

if (is<MyInterface>(foreignObject)) { // returns true
    const someObject = foreignObject.someObject; // type: string
    const without = foreignObject.without; // type: string
}
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;
  }