【问题标题】:How can I create an object based on an interface file definition in TypeScript?如何根据 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"

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

【问题讨论】:

    标签: typescript


    【解决方案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;
                        

                        【讨论】:

                          猜你喜欢
                          • 2018-10-17
                          • 1970-01-01
                          • 2017-07-02
                          • 2018-11-05
                          • 1970-01-01
                          • 2021-01-12
                          • 2019-11-26
                          • 2021-06-08
                          相关资源
                          最近更新 更多