使用接口在TypeScript中输入匿名对象

24

我有一个接口IBase和一个包含一些其他对象的变量(在示例中,我只添加了基础部分以进行更好的演示)

interface IBase {
    height?:number;
    width?:number;
}

var element = {
    base: {

    }
}

如何表达变量element.base所持有的对象属于IBase类型?我知道可以为element变量创建一个包含base等类型的类型,但是是否有可能在不这样做的情况下对该场景进行类型化。

4个回答

31

Van den Brink 的回答很好。这里提供另一个示例选项:

var element = {
    base: <IBase> {

    }
}

这将同时提供所需的智能感知功能:

enter image description here


4
在这里使用类型断言只能部分地带来好处,因为它将允许您强制转换为对象字面量实际上不符合规范的类型。也就是说,它可以让 IntelliSense 起作用,但无法获得良好的静态类型检查。据我所知,唯一获得静态类型检查的方法是将字面量赋值给正确类型的变量,而不使用类型断言。在我看来,Dick van den Brink 给出了更好的答案。 - rationull

12
如果您将var元素的声明更改为以下内容,则它会知道base是什么:
var element: { base: IBase; } = {
    base: {
    }
}
注意:您也可以像这样创建一个新的接口,使其更具可重用性: interface IElement { base: IBase; } 然后像这样使用它: var element: IElement = { base: {} }

9

@basarat的优秀回答现在需要稍作更新;使用尖括号现在会产生tslint错误:

[tslint] 禁止使用'<>'语法进行类型断言。请改用'as'语法。(no-angle-bracket-type-assertion)

解决方案很简单:

const element = {
    base: {} as IBase
}

这还提供了你想要的智能感知(自动完成)功能。

这对我非常有帮助,因为我在寻找一种解决方案时,可以使用默认回退对象来处理通过潜在对象源的空合并运算符(??)。例如:const someData : SomeDataInterface = source1 ?? source2 ?? { /* Defaults */ } : SomeDataInterface - Jesper Hoff
Tslint是指语法被禁止的那个。尖括号仍然是一种非常有效的转换方式。 - smac89

7

你在接口声明方面出现了问题,这是一种你在结构化类型语言中会遇到的微妙问题。

interface IBase {
    height?:number;
    width?:number;
}

因为所有属性都是可选的,因此该接口本质上是 {},即任何对象都满足此接口。这在大多数情况下过于笼统,不太有用。
例如,完全可以这样做:
var x: IBase = {
    a: 'efsdsdf',
    v: 'sdfdsf' 
};

我相信你会同意,这个对象在我想使用IBase对象的任何地方都没有用。

既然这个问题解决了,你可能会发现最优雅的解决方案是创建一个与你的element定义匹配的接口。

interface IElement {
    base: {
        height?:number;
        width?:number;
    }
}

var element: IElement = {
    base: {
        height: 4
    }
}

自此文章发布以来,TypeScript可能已经进行了改进。您的示例确实给我带来了一个错误:类型 '{ a: string; v: string; }' 无法分配给类型 'IBase'。 对象文字只能指定已知属性,并且 'a' 在类型 'IBase' 中不存在。(2322) - Ocie Mitchell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接