Javascript 使用 Typescript 检查接口类型
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14425568/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Interface type check with Typescript
提问by lhk
This question is the direct analogon to Class type check with TypeScript
这个问题是与 TypeScript 的类类型检查的直接类比
I need to find out at runtime if a variable of type any implements an interface. Here's my code:
我需要在运行时找出 any 类型的变量是否实现了接口。这是我的代码:
interface A{
member:string;
}
var a:any={member:"foobar"};
if(a instanceof A) alert(a.member);
If you enter this code in the typescript playground, the last line will be marked as an error, "The name A does not exist in the current scope". But that isn't true, the name does exist in the current scope. I can even change the variable declaration to var a:A={member:"foobar"};without complaints from the editor. After browsing the web and finding the other question on SO I changed the interface to a class but then I can't use object literals to create instances.
如果您在打字稿操场中输入此代码,最后一行将被标记为错误,“名称 A 在当前范围内不存在”。但事实并非如此,该名称确实存在于当前作用域中。我什至可以将变量声明更改为var a:A={member:"foobar"};没有编辑器的抱怨。在浏览网页并在 SO 上找到另一个问题后,我将接口更改为类,但随后我无法使用对象文字来创建实例。
I wondered how the type A could vanish like that but a look at the generated javascript explains the problem:
我想知道类型 A 是如何消失的,但查看生成的 javascript 可以解释这个问题:
var a = {
member: "foobar"
};
if(a instanceof A) {
alert(a.member);
}
There is no representation of A as an interface, therefore no runtime type checks are possible.
没有将 A 表示为接口,因此不可能进行运行时类型检查。
I understand that javascript as a dynamic language has no concept of interfaces. Is there any way to type check for interfaces?
我知道 javascript 作为一种动态语言没有接口的概念。有没有办法对接口进行类型检查?
The typescript playground's autocompletion reveals that typescript even offers a method implements. How can I use it ?
打字稿游乐场的自动完成显示打字稿甚至提供了一个方法implements。我怎样才能使用它?
采纳答案by Fenton
You can achieve what you want without the instanceofkeyword as you can write custom type guards now:
您可以在没有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);
}
Lots of Members
会员多
If you need to check a lot of members to determine whether an object matches your type, you could instead add a discriminator. The below is the most basic example, and requires you to manage your own discriminators... you'd need to get deeper into the patterns to ensure you avoid duplicate discriminators.
如果您需要检查大量成员以确定某个对象是否与您的类型匹配,则可以改为添加鉴别器。以下是最基本的示例,需要您管理自己的鉴别器……您需要更深入地了解模式以确保避免重复鉴别器。
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);
}
回答by vilicvane
In TypeScript 1.6, user-defined type guardwill do the job.
在 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;
}
And just as Joe Yang mentioned: since TypeScript 2.0, you can even take the advantage of tagged union type.
正如 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;
}
And it works with switchtoo.
它也适用switch。
回答by Joe Yang
typescript 2.0 introduce tagged union
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;
}
}
回答by Caleb Macdonald Black
How about User-Defined Type Guards? https://www.typescriptlang.org/docs/handbook/advanced-types.html
用户定义的类型保护怎么样?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();
}
回答by pcan
It's now possible, I just released an enhanced version of the TypeScriptcompiler that provides full reflection capabilities. You can instantiate classes from their metadata objects, retrieve metadata from class constructors and inspect interface/classes at runtime. You can check it out here
现在有可能,我刚刚发布了一个增强版的TypeScript编译器,提供了完整的反射功能。您可以从其元数据对象实例化类,从类构造函数中检索元数据并在运行时检查接口/类。你可以在这里查看
Usage example:
用法示例:
In one of your typescript files, create an interface and a class that implements it like the following:
在您的一个打字稿文件中,创建一个接口和一个实现它的类,如下所示:
interface MyInterface {
doSomething(what: string): number;
}
class MyClass implements MyInterface {
counter = 0;
doSomething(what: string): number {
console.log('Doing ' + what);
return this.counter++;
}
}
now let's print some the list of implemented interfaces.
现在让我们打印一些已实现的接口列表。
for (let classInterface of MyClass.getClass().implements) {
console.log('Implemented interface: ' + classInterface.name)
}
compile with reflec-ts and launch it:
使用 reflect-ts 编译并启动它:
$ node main.js
Implemented interface: MyInterface
Member name: counter - member kind: number
Member name: doSomething - member kind: function
See reflection.d.ts for Interfacemeta-type details.
有关Interface元类型的详细信息,请参阅reflection.d.ts 。
UPDATE:You can find a full working example here
更新:您可以在此处找到完整的工作示例
回答by Dan Dohotaru
same as above where user-defined guardswere used but this time with an arrow function predicate
与上面使用用户定义的守卫相同,但这次使用箭头函数谓词
interface A {
member:string;
}
const check = (p: any): p is A => p.hasOwnProperty('member');
var foo: any = { member: "foobar" };
if (check(foo))
alert(foo.member);
回答by DS.
Here's another option: the module ts-interface-builderprovides a build-time tool that converts a TypeScript interface into a runtime descriptor, and ts-interface-checkercan check if an object satisfies it.
这是另一个选项:模块ts-interface-builder提供了一个构建时工具,可以将 TypeScript 接口转换为运行时描述符,并且ts-interface-checker可以检查对象是否满足它。
For OP's example,
对于 OP 的示例,
interface A {
member: string;
}
You'd first run ts-interface-builderwhich produces a new concise file with a descriptor, say, foo-ti.ts, which you can use like this:
您首先运行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"
You can create a one-liner type-guard function:
您可以创建一个单行类型保护功能:
function isA(value: any): value is A { return A.test(value); }
回答by Daniel Ribeiro
I would like to point out that TypeScript does not provide a direct mechanism for dynamically testing whether an object implements a particular interface.
我想指出的是,TypeScript 没有提供动态测试对象是否实现特定接口的直接机制。
Instead, TypeScript code can use the JavaScript technique of checking whether an appropriate set of members are present on the object. For example:
相反,TypeScript 代码可以使用 JavaScript 技术来检查对象上是否存在一组合适的成员。例如:
var obj : any = new Foo();
if (obj.someInterfaceMethod) {
...
}
回答by Dmitry Matveev
TypeGuards
类型保护
interface MyInterfaced {
x: number
}
function isMyInterfaced(arg: any): arg is MyInterfaced {
return arg.x !== undefined;
}
if (isMyInterfaced(obj)) {
(obj as MyInterfaced ).x;
}
回答by aledpardo
Based on Fenton's answer, here's my implementation of a function to verify if a given objecthas the keys an interfacehas, both fully or partially.
基于 Fenton 的回答,这是我对一个函数的实现,用于验证给定object的密钥interface是否全部或部分具有。
Depending on your use case, you may also need to check the types of each of the interface's properties. The code below doesn't do that.
根据您的用例,您可能还需要检查每个接口属性的类型。下面的代码不会这样做。
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;
}
Example of usage:
用法示例:
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

