使用Typescript检查接口类型

这个问题直接类似于使用TypeScript检查类类型

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

interface A{
member:string;
}


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


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

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

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

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

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

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

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

643369 次浏览

你可以在没有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);
}

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

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

var obj : any = new Foo();


if (obj.someInterfaceMethod) {
...
}

现在这是可能的,我刚刚发布了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

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

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

在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;
}

它也适用于switch

Typescript 2.0引入了带标签的联合

Typescript 2.0 features . b0

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;
}
}

用户定义类型保护呢?# EYZ0

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();
}

TypeGuards

interface MyInterfaced {
x: number
}


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


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

这里还有另一个选项:模块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); }

与上面使用用户定义的警卫相同,但这次使用了一个箭头函数谓词

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);

因为在运行时类型是未知的,所以我写了如下代码来比较未知对象,不是与类型进行比较,而是与已知类型的对象进行比较:

  1. 创建正确类型的示例对象
  2. 指定它的哪些元素是可选的
  3. 将你的未知对象与这个样本对象进行深度比较

下面是我用于深度比较的(接口不可知)代码:

function assertTypeT<T>(loaded: any, wanted: T, optional?: Set<string>): T {
// this is called recursively to compare each element
function assertType(found: any, wanted: any, keyNames?: string): void {
if (typeof wanted !== typeof found) {
throw new Error(`assertType expected ${typeof wanted} but found ${typeof found}`);
}
switch (typeof wanted) {
case "boolean":
case "number":
case "string":
return; // primitive value type -- done checking
case "object":
break; // more to check
case "undefined":
case "symbol":
case "function":
default:
throw new Error(`assertType does not support ${typeof wanted}`);
}
if (Array.isArray(wanted)) {
if (!Array.isArray(found)) {
throw new Error(`assertType expected an array but found ${found}`);
}
if (wanted.length === 1) {
// assume we want a homogenous array with all elements the same type
for (const element of found) {
assertType(element, wanted[0]);
}
} else {
// assume we want a tuple
if (found.length !== wanted.length) {
throw new Error(
`assertType expected tuple length ${wanted.length} found ${found.length}`);
}
for (let i = 0; i < wanted.length; ++i) {
assertType(found[i], wanted[i]);
}
}
return;
}
for (const key in wanted) {
const expectedKey = keyNames ? keyNames + "." + key : key;
if (typeof found[key] === 'undefined') {
if (!optional || !optional.has(expectedKey)) {
throw new Error(`assertType expected key ${expectedKey}`);
}
} else {
assertType(found[key], wanted[key], expectedKey);
}
}
}


assertType(loaded, wanted);
return loaded as T;
}


下面是我如何使用它的一个例子。

在本例中,我希望JSON包含一个元组数组,其中第二个元素是一个名为User的接口实例(它有两个可选元素)。

TypeScript的类型检查将确保我的示例对象是正确的,然后assertTypeT函数检查未知(从JSON加载的)对象是否与示例对象匹配。

export function loadUsers(): Map<number, User> {
const found = require("./users.json");
const sample: [number, User] = [
49942,
{
"name": "ChrisW",
"email": "example@example.com",
"gravatarHash": "75bfdecf63c3495489123fe9c0b833e1",
"profile": {
"location": "Normandy",
"aboutMe": "I wrote this!\n\nFurther details are to be supplied ..."
},
"favourites": []
}
];
const optional: Set<string> = new Set<string>(["profile.aboutMe", "profile.location"]);
const loaded: [number, User][] = assertTypeT(found, [sample], optional);
return new Map<number, User>(loaded);
}


您可以在用户定义的类型保护的实现中调用这样的检查。

基于Fenton的回答,这里是我实现的一个函数,用于验证给定的object是否具有interface所具有的全部或部分键。

根据您的用例,您可能还需要检查每个接口属性的类型。下面的代码不会这样做。

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;
}

用法示例:

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
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;
}

你可以在运行时使用ts-validate-type验证TypeScript类型,就像这样(虽然需要Babel插件):

const user = validateType<{ name: string }>(data);
使用字符串文字是困难的,因为如果你想重构你的方法或接口名称,那么你的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类中仍然存在该方法

下面是我使用类和lodash提出的解决方案:(它工作!)

// TypeChecks.ts
import _ from 'lodash';


export class BakedChecker {
private map: Map<string, string>;


public constructor(keys: string[], types: string[]) {
this.map = new Map<string, string>(keys.map((k, i) => {
return [k, types[i]];
}));
if (this.map.has('__optional'))
this.map.delete('__optional');
}


getBakedKeys() : string[] {
return Array.from(this.map.keys());
}


getBakedType(key: string) : string {
return this.map.has(key) ? this.map.get(key) : "notfound";
}
}


export interface ICheckerTemplate {
__optional?: any;
[propName: string]: any;
}


export function bakeChecker(template : ICheckerTemplate) : BakedChecker {
let keys = _.keysIn(template);
if ('__optional' in template) {
keys = keys.concat(_.keysIn(template.__optional).map(k => '?' + k));
}
return new BakedChecker(keys, keys.map(k => {
const path = k.startsWith('?') ? '__optional.' + k.substr(1) : k;
const val = _.get(template, path);
if (typeof val === 'object') return val;
return typeof val;
}));
}


export default function checkType<T>(obj: any, template: BakedChecker) : obj is T {
const o_keys = _.keysIn(obj);
const t_keys = _.difference(template.getBakedKeys(), ['__optional']);
return t_keys.every(tk => {
if (tk.startsWith('?')) {
const ak = tk.substr(1);
if (o_keys.includes(ak)) {
const tt = template.getBakedType(tk);
if (typeof tt === 'string')
return typeof _.get(obj, ak) === tt;
else {
return checkType<any>(_.get(obj, ak), tt);
}
}
return true;
}
else {
if (o_keys.includes(tk)) {
const tt = template.getBakedType(tk);
if (typeof tt === 'string')
return typeof _.get(obj, tk) === tt;
else {
return checkType<any>(_.get(obj, tk), tt);
}
}
return false;
}
});
}

自定义类:

// MyClasses.ts


import checkType, { bakeChecker } from './TypeChecks';


class Foo {
a?: string;
b: boolean;
c: number;


public static _checker = bakeChecker({
__optional: {
a: ""
},
b: false,
c: 0
});
}


class Bar {
my_string?: string;
another_string: string;
foo?: Foo;


public static _checker = bakeChecker({
__optional: {
my_string: "",
foo: Foo._checker
},
another_string: ""
});
}

在运行时检查类型:

if (checkType<Bar>(foreign_object, Bar._checker)) { ... }

我在文件filter-descriptor.interface.d.ts中找到了@progress/kendo-data-query中的一个例子

检查程序

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

示例使用

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


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

Typescript中的类型保护:

TS使用类型警卫来实现这个目的。他们是这样定义的:

执行运行时检查以保证类型的表达式

.在某些范围内

这基本上意味着TS编译器在拥有足够的信息时可以将类型缩小到更特定的类型。例如:

function foo (arg: number | string) {
if (typeof arg === 'number') {
// fine, type number has toFixed method
arg.toFixed()
} else {
// Property 'toFixed' does not exist on type 'string'. Did you mean 'fixed'?
arg.toFixed()
// TSC can infer that the type is string because
// the possibility of type number is eliminated at the if statement
}
}

回到您的问题,我们还可以将类型保护的概念应用于对象,以确定它们的类型。要为对象定义类型保护,我们需要定义一个返回类型为类型谓词的函数。例如:

interface Dog {
bark: () => void;
}


// The function isDog is a user defined type guard
// the return type: 'pet is Dog' is a type predicate,
// it determines whether the object is a Dog
function isDog(pet: object): pet is Dog {
return (pet as Dog).bark !== undefined;
}


const dog: any = {bark: () => {console.log('woof')}};


if (isDog(dog)) {
// TS now knows that objects within this if statement are always type Dog
// This is because the type guard isDog narrowed down the type to Dog
dog.bark();
}

在我看来,这是最好的方法;附上一个“;Fubber"符号到接口。它的编写速度要快得多,对于JavaScript引擎来说,它比类型保护快得多,它支持接口的继承,如果你需要的话,它使类型保护易于编写。

这就是ES6有符号的目的。

接口

// Notice there is no naming conflict, because interfaces are a *type*
export const IAnimal = Symbol("IAnimal");
export interface IAnimal {
[IAnimal]: boolean; // the fubber
}


export const IDog = Symbol("IDog");
export interface IDog extends IAnimal {
[IDog]: boolean;
}


export const IHound = Symbol("IDog");
export interface IHound extends IDog {
// The fubber can also be typed as only 'true'; meaning it can't be disabled.
[IDog]: true;
[IHound]: boolean;
}

import { IDog, IAnimal } from './interfaces';
class Dog implements IDog {
// Multiple fubbers to handle inheritance:
[IAnimal] = true;
[IDog] = true;
}


class Hound extends Dog implements IHound {
[IHound] = true;
}

测试

如果你想帮助TypeScript编译器,这段代码可以放在类型保护中。

import { IDog, IAnimal } from './interfaces';


let dog = new Dog();


if (dog instanceof Hound || dog[IHound]) {
// false
}
if (dog[IAnimal]?) {
// true
}


let houndDog = new Hound();


if (houndDog[IDog]) {
// true
}


if (dog[IDog]?) {
// it definitely is a dog
}


答案很简单。然而,这种解决方案至少在大约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
}

在Typescript中使用Reflect进行类型保护

下面是一个来自我的Typescript游戏引擎的类型保护的例子

 export interface Start {
/**
* Start is called on the frame when a script is enabled just before any of the Update methods are called the first time.
*/
start(): void
}




/**
* User Defined Type Guard for Start
*/
export const implementsStart = (arg: any): arg is Start => {
return Reflect.has(arg, 'start')
}




/**
* Example usage of the type guard
*/


start() {
this.components.forEach(component => {
if (implementsStart(component)) {
component.start()
}


})
}

自OP以来将近9年,这个问题仍然存在。我真的很想爱上Typescript。通常我都能成功。但它在打字安全方面的漏洞是我捏着的鼻子挡不住的恶臭。

我的解决方案并不完美。但我的观点是,它们比大多数更常用的解决方案要好。鉴别符已被证明是一种糟糕的实践,因为它们限制了可伸缩性并完全违背了类型安全的目的。我的两个最漂亮的解决方案是,按顺序排列:

< p >类修饰符: 递归地扫描类型化对象的成员,并基于符号名计算散列。将散列与静态KVP属性中的类型名称关联。在哈希计算中包括类型名称,以减少与祖先的歧义风险(发生在空子类中)。 优点:它被证明是最值得信赖的。它还提供非常严格的执行。这也类似于其他高级语言本机实现多态性的方式。但是,为了真正具有多态性,该解决方案还需要进一步扩展。 缺点:匿名/JSON对象必须在每次类型检查时重新散列,因为它们没有类型定义来关联和静态缓存。在高负载场景下,过多的堆栈开销会导致严重的性能瓶颈。可以使用IoC容器来缓解,但对于没有其他理由的小型应用程序来说,这也可能是不可取的开销。

.

.

. < p >克隆: 虽然很丑,但经过深思熟虑的策略是有益的。创建类型化对象的新实例,并反射性地从匿名对象复制顶级成员赋值。给定一个预定的传递标准,您可以同时检查和克隆转换类型。类似于“tryparse”;来自其他语言。 优点:在某些情况下,立即使用转换后的“test”可以减少资源开销;实例。不需要额外的勤奋装修。大量的灵活性公差。 缺点:内存像面粉筛一样漏出来。没有“deep”;克隆、突变的引用可以破坏其他组件,而不会预料到封装的破坏。静态缓存不适用,因此在每个调用上执行操作——具有大量顶级成员的对象将影响性能。Typescript新手开发人员会误以为你是新手,因为他们不理解你为什么要写这种模式

总而言之:我不买“JS不支持它”;为Typescript在多态性上的细微差别找借口。转发器绝对适合这个目的。用盐来疗伤:它来自微软。他们在许多年前就已经解决了这个问题,并且取得了巨大的成功:. net框架提供了一个健壮的互操作API,可以向后兼容COM和ActiveX。它们没有尝试编译到旧的运行时。对于像JS这样松散的解释性语言来说,这种解决方案要容易得多,也不那么混乱……然而,由于害怕输给其他超级明星,他们退缩了。使用JS中本应由TS解决的缺点,作为重新定义静态类型面向对象原则的畸形基础,是毫无意义的。它与大量行业领先的文档和规范背道而驰,这些文档和规范几十年来一直为高级软件开发提供信息。

我知道我偶然发现了一个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
}

简单的解决方案,与选择解决方案有相同的缺点,但这个变体捕捉JS错误,只接受对象作为参数,并有一个有意义的返回值。

interface A{
member:string;
}


const implementsA = (o: object): boolean => {
try {
return 'member' in o;
} catch (error) {
return false;
}
}


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


implementsA(a) && console.log("a implements A");
// implementsA("str"); // causes TS transpiler error

另一种解决方案可能与HTMLIFrameElement接口的情况类似。如果我们知道在另一个模块中有它的实现,我们可以通过在接口旁边创建一个对象来声明一个同名的变量。

declare var HTMLIFrameElement: {
prototype: HTMLIFrameElement;
new(): HTMLIFrameElement;
};

在这种情况下

interface A {
member:string;
}


declare var A : {
prototype: A;
new(): A;
};


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

应该没问题

你也可以向子组件发送多个输入,其中一个是鉴别器,另一个是实际数据,并检查子组件中的鉴别器,如下所示:

@Input() data?: any;
@Input() discriminator?: string;


ngOnInit(){
if(this.discriminator = 'InterfaceAName'){
//do stuff
}
else if(this.discriminator = 'InterfaceBName'){
//do stuff
}
}

显然,你可以把它移动到任何它适用的地方,比如ngOnChanges函数或setter函数,但这个想法仍然成立。如果你想要一个响应式表单,我还建议尝试将ngModel绑定到输入数据上。你可以使用这些if语句根据传入的数据来设置ngModel,并在html中反映:

<div [(ngModel)]=\{\{dataModel}}>
<div *ngFor="let attr of (data | keyvalue)">
<!--You can use attr.key and attr.value in this situation to display the attributes of your interface, and their associated values from the data -->
</div>
</div>

或者用这个代替:

<div *ngIf = "model == 'InterfaceAName'">
<div>Do This Stuff</div>
</div>
<div *ngIf= "model == 'IntefaceBName'">
<div>Do this instead</div>
</div>

(您可以使用attr。键和attr。值在这种情况下显示接口的属性,以及它们从数据中关联的值)

我知道这个问题已经有了答案,但我认为这可能对试图构建半模糊的角形式的人有用。你也可以将此用于角材料模块(例如对话框),通过数据参数发送两个变量——一个是你的实际数据,另一个是判别器,并通过类似的过程检查它。最终,这将允许您创建一个表单,并围绕流入其中的数据塑造表单。

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

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

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