这个问题直接类似于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甚至提供了一个方法实现。我怎么使用它?
我知道我偶然发现了一个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
}
使用字符串文字是很困难的,因为如果你想重构你的方法或接口名称,那么你的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 1.6中,用户定义的类型保护将完成这项工作。
interface Foo {
fooProperty: string;
}
interface Bar {
barProperty: string;
}
function isFoo(object: any): object is Foo {
return 'fooProperty' in object;
}
let object: Foo | Bar;
if (isFoo(object)) {
// `object` has type `Foo`.
object.fooProperty;
} else {
// `object` has type `Bar`.
object.barProperty;
}
正如Joe Yang提到的:从TypeScript 2.0开始,你甚至可以利用带标签的联合类型。
interface Foo {
type: 'foo';
fooProperty: string;
}
interface Bar {
type: 'bar';
barProperty: number;
}
let object: Foo | Bar;
// You will see errors if `strictNullChecks` is enabled.
if (object.type === 'foo') {
// object has type `Foo`.
object.fooProperty;
} else {
// object has type `Bar`.
object.barProperty;
}
它也适用于开关。
答案很简单。然而,这种解决方案至少在大约3/4的情况下是可能的(尽管并不总是理想的)。所以,换句话说,这可能与阅读这篇文章的人有关。
假设我有一个非常简单的函数,需要知道参数的接口类型:
const simpleFunction = (canBeTwoInterfaces: interfaceA | interface B) => {
// if interfaceA, then return canBeTwoInterfaces.A
// if interfaceB, then return canBeTwoInterfaces.B
}
得到最多赞的答案往往是使用“功能检查”。也就是说,
const simpleFunction = (canBeTwoInterfaces: interfaceA | interface B) => {
if (canBeTwoInterfaces.onlyExistsOnInterfaceA) return canBeTwoInterfaces.A
else return canBeTwoInterfaces.B
}
然而,在我正在使用的代码库中,我需要检查的接口主要包含可选参数。另外,我团队里的其他人可能会在我不知情的情况下突然改名字。如果这听起来像您正在使用的代码库,那么下面的函数要安全得多。
就像我之前说的,这对很多人来说可能是一件非常明显的事情。尽管如此,要知道何时何地应用给定的解决方案并不明显,不管它是否恰好像下面这样非常简单。
这就是我要做的:
const simpleFunction = (
canBeTwoInterfaces: interfaceA | interface B,
whichInterfaceIsIt: 'interfaceA' | 'interfaceB'
) => {
if (whichInterfaceIsIt === 'interfaceA') return canBeTwoInterface.A
else return canBeTwoInterfaces.B
}