我已经定义了这样的界面:
interface IModal {
content: string;
form: string;
href: string;
$form: JQuery;
$message: JQuery;
$modal: JQuery;
$submits: JQuery;
}
我定义了一个这样的变量:
var modal: IModal;
但是,当我尝试设置模态的属性时,它会给我一条消息说
"cannot set property content of undefined"
是否可以使用界面来描述我的模态对象,如果可以,我该如何创建呢?
答案 0 :(得分:305)
如果您在其他地方创建“模态”变量,并想告诉TypeScript它将全部完成,您可以使用:
declare const modal: IModal;
如果你想在TypeScript中创建一个实际上是IModal实例的变量,你需要完全定义它。
const modal: IModal = {
content: '',
form: '',
href: '',
$form: null,
$message: null,
$modal: null,
$submits: null
};
或者谎言,使用类型断言,但是你将失去类型安全性,因为你现在将在意外的地方得到未定义,并且可能在访问modal.content
等时遇到运行时错误(合同说的属性将会在那里。
const modal = {} as IModal;
示例类
class Modal implements IModal {
content: string;
form: string;
href: string;
$form: JQuery;
$message: JQuery;
$modal: JQuery;
$submits: JQuery;
}
const modal = new Modal();
你可能会认为“嘿,这真的是一个重复的界面” - 你是对的。如果Modal类是IModal接口的唯一实现,您可能想要完全删除该接口并使用...
const modal: Modal = new Modal();
而不是
const modal: IModal = new Modal();
答案 1 :(得分:159)
如果你想要一个接口的空对象,你可以这样做:
var modal = <IModal>{};
使用接口代替类来构造数据的优点是,如果你没有在类上有任何方法,它将在编译的JS中显示为一个空方法。例如:
class TestClass {
a: number;
b: string;
c: boolean;
}
编译成
var TestClass = (function () {
function TestClass() {
}
return TestClass;
})();
没有任何价值。另一方面,接口根本不会出现在JS中,同时仍然提供数据结构和类型检查的好处。
答案 2 :(得分:35)
如果您正在使用React,解析器将会扼杀传统的强制转换语法,因此引入了替代方法,以便在 .tsx 文件中使用
let a = {} as MyInterface;
答案 3 :(得分:16)
我认为你基本上有五种不同的选择。根据您希望实现的目标,在其中进行选择可能很容易。
大多数情况下使用类并实例化的最佳方法,因为您使用TypeScript来应用类型检查。
interface IModal {
content: string;
form: string;
//...
//Extra
foo: (bar: string): void;
}
class Modal implements IModal {
content: string;
form: string;
foo(param: string): void {
}
}
即使其他方法提供了更简单的方法来从界面创建对象,您应该考虑将拆分界面分开,如果您将对象用于不同的事情,并且它不会导致界面结束-segregation:
interface IBehaviour {
//Extra
foo(param: string): void;
}
interface IModal extends IBehaviour{
content: string;
form: string;
//...
}
另一方面,例如在单元测试代码期间(如果您可能不经常分离关注点),您可能会为了提高生产率而接受这些缺点。您可以应用其他方法来创建主要用于大型第三方* .d.ts接口的模拟。总是为每个巨大的界面实现完整的匿名对象可能会很痛苦。
在此路径上,您的第一个选择是创建一个空对象:
var modal = <IModal>{};
其次要完全实现界面的必备部分。无论您是在调用第三方JavaScript库,都会很有用,但我认为您应该像以前一样创建一个类:
var modal: IModal = {
content: '',
form: '',
//...
foo: (param: string): void => {
}
};
第三,您只需创建部分界面并创建匿名对象,但这样您就有责任履行合同
var modal: IModal = <any>{
foo: (param: string): void => {
}
};
总结我的答案,即使接口是可选的,因为它们不会被转换为JavaScript代码,如果明智且一致地使用,TypeScript可以提供新的抽象级别。我想,只是因为你可以在大多数情况下从你自己的代码中解雇它们,你不应该这样做。
答案 4 :(得分:15)
你可以做到
var modal = {} as IModal
答案 5 :(得分:7)
由于我没有在顶部找到一个平等的答案,我的答案是不同的。 我这样做:
modal: IModal = <IModal>{}
答案 6 :(得分:3)
您可以使用Class
设置默认值。
interface IModal {
content: string;
form: string;
href: string;
isPopup: boolean;
};
class Modal implements IModal {
content = "";
form = "";
href: string; // will not be added to object
isPopup = true;
}
const myModal = new Modal();
console.log(myModal); // output: {content: "", form: "", isPopup: true}
interface IModal {
content: string;
form: string;
href: string;
isPopup: boolean;
}
class Modal implements IModal {
constructor() {
this.content = "";
this.form = "";
this.isPopup = true;
}
content: string;
form: string;
href: string; // not part of constructor so will not be added to object
isPopup: boolean;
}
const myModal = new Modal();
console.log(myModal); // output: {content: "", form: "", isPopup: true}
答案 7 :(得分:2)
这是另一种方法:
您可以像这样简单地创建一个ESLint友好对象
const modal: IModal = {} as IModal;
或基于接口的默认实例,并具有合理的默认值(如果有)
const defaultModal: IModal = {
content: "",
form: "",
href: "",
$form: {} as JQuery,
$message: {} as JQuery,
$modal: {} as JQuery,
$submits: {} as JQuery
};
然后只需覆盖某些属性即可更改默认实例的变体
const confirmationModal: IModal = {
...defaultModal, // all properties/values from defaultModal
form: "confirmForm" // override form only
}
答案 8 :(得分:2)
由于问题包括TypeScript的使用,替换
var modal: IModal;
由
let modal: IModal = {} as IModal;
应该回答问题。
答案 9 :(得分:1)
使用您的界面即可
class Modal() {
constructor(public iModal: IModal) {
//You now have access to all your interface variables using this.iModal object,
//you don't need to define the properties at all, constructor does it for you.
}
}
答案 10 :(得分:0)
到目前为止,发布的许多解决方案都使用类型断言,因此,如果在实现中省略了必需的接口属性,则不会引发编译错误。
对于那些对其他鲁棒,紧凑型解决方案感兴趣的人:
选项1:实例化一个实现该接口的匿名类:
new class implements MyInterface {
nameFirst = 'John';
nameFamily = 'Smith';
}();
选项2:创建实用程序功能:
export function impl<I>(i: I) { return i; }
impl<MyInterface>({
nameFirst: 'John';
nameFamily: 'Smith';
})
答案 11 :(得分:0)
这里是我经常使用的另一种解决方案。但是,我不确定这是否是一种好的做法,否则请在下面评论。
/// Interface
export default interface BookInterface {
title: string,
author: string,
id: any
}
/// Creating Class
export class BookClass implements BookInterface {
title: string;
author: string;
id: any;
constructor(title: string, author: string, id: any) {
this.title = title;
this.author = author;
this.id = id;
}
}
/// How to use it
let book: BookInterface = new BookClass(title, author, id);
谢谢:)
答案 12 :(得分:0)
您实际上不需要类来创建对象。你可以直接这样做:
interface IModal {
content: string;
form: string;
}
onButtonSaveClick() {
let myModalClass: IModal = {
content: 'foo content',
form: 'foo form'
}
}