如何根据 TypeScript 中的接口文件定义创建对象?

Posted

技术标签:

【中文标题】如何根据 TypeScript 中的接口文件定义创建对象?【英文标题】:How can I create an object based on an interface file definition in TypeScript? 【发布时间】:2012-10-20 00:10:46 【问题描述】:

我已经定义了一个这样的接口:

interface IModal 
    content: string;
    form: string;
    href: string;
    $form: JQuery;
    $message: JQuery;
    $modal: JQuery;
    $submits: JQuery;
 

我这样定义一个变量:

var modal: IModal;

但是,当我尝试设置 modal 的属性时,它会给我一条消息,说

"cannot set property content of undefined"

是否可以使用接口来描述我的模态对象,如果可以,我应该如何创建它?

【问题讨论】:

【参考方案1】:

如果你在别处创建“modal”变量,并且想告诉 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();

【讨论】:

谢谢。我希望不必最初定义所有模态内容。如果我将 Modal 定义为具有属性的类,然后使用 new 和构造函数来设置所有初始值而不是接口,会更容易吗? 是的 - 您可以定义一个类,然后您只需在需要时创建新实例。你需要一个例子吗? 我已经添加了一个示例和关于界面的注释。 var modal = <IModal>; 这就是我要找的 ;-) 谢谢! 仅供参考,最好使用 as IModal 而不是<IModal>。在 JSX 中使用 <foo> 样式断言时,它消除了语言语法中的歧义。 Read more。当然,使用letconst 而不是var【参考方案2】:

如果你想要一个接口的空对象,你可以这样做:

var modal = <IModal>;

使用接口代替类来构造数据的好处是,如果类上没有任何方法,它将在编译的 JS 中显示为空方法。示例:

class TestClass 
    a: number;
    b: string;
    c: boolean;

编译成

var TestClass = (function () 
    function TestClass() 
    
    return TestClass;
)();

没有任何价值。另一方面,接口根本不会出现在 JS 中,同时仍然提供数据结构化和类型检查的好处。

【讨论】:

` 添加到上述评论。要调用函数“updateModal(IModal modalInstance) ”,您可以创建接口 'IModal' 的内联实例,如下所示: //这里有一些代码,其中 updateModal 函数和 IModal 可以访问: updateModal( //此行创建一个实例 content: '', form: '', href: '', $form: null, $message: null, $modal: null, $submits: null ); //完成你的代码` 通过使用var modal= &lt;abc&gt;,我们刚刚分配了空对象的 abc 类型的模态,但是我们在哪里声明了模态的类型?我正在使用 typescript6。 这对我不起作用,我必须按照接受的答案中的说明初始化整个对象。【参考方案3】:

如果你使用 React,解析器会阻塞传统的强制转换语法,因此引入了一种替代方法,用于 .tsx 文件

let a =  as MyInterface;

https://www.typescriptlang.org/docs/handbook/jsx.html

【讨论】:

【参考方案4】:

我认为您基本上有 五种不同的选择可以这样做。根据您想要实现的目标,在其中进行选择可能很容易。

在大多数情况下使用类并实例化它的最佳方式,因为您使用 TypeScript 来应用类型检查。

interface IModal 
    content: string;
    form: string;
    //...

    //Extra
    foo: (bar: string): void;


class Modal implements IModal 
    content: string;
    form: string;

    foo(param: string): void 
    

即使其他方法提供了从接口创建对象的更简单方法,您也应该考虑拆分接口,如果您将对象用于不同的事情,并且不会导致接口溢出-隔离:

interface IBehaviour 
    //Extra
    foo(param: string): void;


interface IModal extends IBehaviour
    content: string;
    form: string;
    //...

另一方面,例如在对代码进行单元测试期间(如果您可能不经常应用关注点分离),您可能会为了提高工作效率而接受这些缺点。您可以应用其他方法来创建主要用于大型第三方 *.d.ts 接口的模拟。而且总是为每个巨大的接口实现完全匿名的对象可能会很痛苦。

在这条路径上,您的第一个选择是创建一个空对象

 var modal = <IModal>;

其次是完全实现你界面的强制部分。是否调用 3rd 方 javascript 库会很有用,但我认为你应该创建一个类,就像以前一样:

var modal: IModal = 
    content: '',
    form: '',
    //...

    foo: (param: string): void => 
    
;

第三,您可以只创建界面的一部分并创建一个匿名对象,但这样您有责任履行合同

var modal: IModal = <any>
    foo: (param: string): void => 

    
;

总结一下我的回答,即使接口是可选的,因为它们没有被转换成 JavaScript 代码,TypeScript 可以提供一个新的抽象级别,如果使用得当且一致的话。我认为,仅仅因为在大多数情况下你可以从你自己的代码中忽略它们,你不应该这样做。

【讨论】:

【参考方案5】:

你可以的

var modal =  as IModal 

【讨论】:

【参考方案6】:

这是另一种方法:

你可以像这样简单地创建一个 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

【讨论】:

【参考方案7】:

由于我在顶部没有找到相同的答案,所以我的答案不同。 我愿意:

modal: IModal = <IModal>

【讨论】:

【参考方案8】:

迄今为止发布的许多解决方案都使用类型断言,因此如果在实现中省略了所需的接口属性,则不会引发编译错误。

对于那些对其他一些强大、紧凑的解决方案感兴趣的人:

选项1:实例化一个实现接口的匿名类:

new class implements MyInterface 
  nameFirst = 'John';
  nameFamily = 'Smith';
();

选项 2:创建效用函数:

export function impl<I>(i: I)  return i; 

impl<MyInterface>(
  nameFirst: 'John';
  nameFamily: 'Smith';
)

【讨论】:

【参考方案9】:

您可以使用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

【讨论】:

【参考方案10】:

由于问题包括 TypeScript 的使用,替换

var modal: IModal;

通过

let modal: IModal =  as IModal;

应该回答问题。

【讨论】:

不,创建一个空对象:modal = ;里面没有属性。【参考方案11】:

使用您的界面,您可以做到

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.
  

【讨论】:

【参考方案12】:

这是我经常使用的另一种解决方案。但是我不确定是否是好的做法,如果不是,请在下面评论。

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

谢谢:)

【讨论】:

基本上这是不好的做法,因为接口只在编译时使用,导致 js 文件变小,而类将被编译为 js 类(函数),这增加了代码和复杂性【参考方案13】:

您实际上不需要类来创建对象。你可以直接这样做:

interface IModal 
    content: string;
    form: string;


onButtonSaveClick() 
    let myModalClass: IModal = 
        content: 'foo content',
        form: 'foo form'
    

【讨论】:

【参考方案14】:

界面有5种使用方式。

interface IStudent 
      Id: number;
      name: string;
    
    
    
    Method 1. all fields must assign data.
     const  obj1: IStudent =  Id: 1, name: 'Naveed' ;  
    
    Method 2. my favorite one
    const obj2 =  name: 'Naveed'  as IStudent ;
    
    Method 3.
    const obj3 = <IStudent >name: 'Naveed'; 
    
    Method 4. use partial interface if all fields not required.
    const  obj4: Partial<IStudent > =  name: 'Naveed' ;  
    
    Method 5. use ? Mark with interface fields if all fields not required.
    const  obj5: IStudent =   name: 'Naveed' ;  

【讨论】:

【参考方案15】:
let deletedQuestionsDto =  examId: this.examId, questionId: q.id  as DeletedQuestionsDto;

【讨论】:

以上是关于如何根据 TypeScript 中的接口文件定义创建对象?的主要内容,如果未能解决你的问题,请参考以下文章

深入浅出TypeScript- 使用接口和类型别名

Mongoose Schema 类型作为 TypeScript 的自定义接口?

如何根据 Aurelia/Typescript 中的嵌套属性对对象数组进行排序

在 Typescript 中实现接口时如何定义私有属性?

我可以基于 TypeScript 中的另一个接口以某种方式定义接口中的索引名称吗?

如何使用 TypeScript 在接口中定义对象的命名数组?