【问题标题】:How to set optional class parameters in Angular 2-Typescript?如何在 Angular 2-Typescript 中设置可选的类参数?
【发布时间】:2016-04-20 14:22:12
【问题描述】:

我知道在Typescript中可选参数可以用问号标记。

但是,我发现使用 new 关键字实际实例化类的唯一方法。

问题在于,基于 Angular 2 的入门“英雄”教程类通过 new 关键字实例化,据我所知,这是由 Angular 内部完成的。

例如我有这个代码:

models/users.ts

export class User {
    id: number;
    name: string; // I want this to be optional
}

models/mock-users.ts

import {User} from './user';

export var USERS: User[] = [
    {
       id: 1
       // no name (I wanted it to be optional for user with id 1)
    },
    {
       id: 2,
       name: "User 2"
    },        
]

services/user.service.ts

import {Injectable} from 'angular2/core';
import {USERS} from './../models/mock-users';

@Injectable()
export class UserService {
    getUsers() {
         return Promise.resolve(USERS);
    }
}

views/my-component.component.ts

// imports here...

@Component({
   // ...
})

export class MyComponent {
   constructor(private _userService: UserService) { }

   getUsers() {
         this._userService.getUsers().then(users => console.log(users));
   }
}

【问题讨论】:

    标签: typescript angular


    【解决方案1】:

    在您的情况下,改为使用用户界面可能更方便。

    export interface User {
        id: number;
        name?: string; // interfaces allow fields to be optional
    }
    

    当我想定义对象的“形状”时,我使用接口,当我需要添加行为(方法)时使用类。如果您只需要移动数据,我会使用界面。

    如果你确实需要一个类,那么在mock-users.ts 中创建用户实例的语法应该有点不同。首先,TypeScript 中没有“可选的类字段”。任何字段都不能设置/“未定义”,因此将字段标记为可选是没有意义的。您可以使用 new 关键字实例化一个类 - 缺点是您需要编写构造函数来设置字段值或将实例分配给变量并设置字段。但是使用 new 关键字并没有错,尤其是对于测试对象。

    您还可以像在mock-users.ts 中所做的那样,使用对象文字实例化一个对象 - 您需要通过添加强制转换来更加明确。

    export var USERS: User[] = [
        <User> { // explicit cast to let the TypeScript compiler know you know what you're doing
           id: 1
           // no name (I wanted it to be optional for user with id 1)
        },
        {
           id: 2,
           name: "User 2"
        },        
    ]
    

    没有强制转换,TypeScript 编译器将产生错误。这是为了捕捉错误而设计的。如果你想了解更多(有趣的)原因,这里有一个关于类型检查背后的一些思考的相关详细讨论:

    【讨论】:

    • 谢谢 Ronald。能否提供一个完整的例子(用法)?
    • 如果您拥有的所有代码都在问题中,那么将关键字从 class 更改为 interface 应该可以解决问题。我会扩展答案。
    • 感谢您的进一步解释。我会去做的。你能解释一下当我想要可选参数和方法时我应该怎么做?另外,对于具有方法的类,我是否需要使用新的键进行实例化?在此之后我会接受你的回答:)
    • 感谢您的进一步解释。正如承诺的那样,我接受了答案。你能定义“匿名对象”吗?
    • 对不起,正确的术语是“对象文字”。 “匿名对象”一词来自 C# 语言,我也非常喜欢它。对象字面量只是内联定义的对象,例如 { id: 1, 'name: 'John' }
    【解决方案2】:

    另一种方法是使用Object.assign 来扩展具有您只需要的属性的有效类型化对象(在此示例中省略属性ac

    export class A {
        a:number=1;
        b:number;
        c:string;
        d:string;
    }
    
    let validA:A = Object.assign(new A(),{
        b:3,
        d:'Lorem ipsum'
    });
    

    我个人更喜欢这种语法来避免多行对象初始化和为我的应用程序的每个模型创建接口的无聊事情(如果存在对应的类,那么另一个文件将毫无用处)。

    此外,不要犹豫,在你的类定义中设置默认值,即使在这种情况下它不是强制性的。

    最后一件重要的事情是,在这种情况下您不要松散类方法(与 {} 强制转换相反)

    【讨论】:

      【解决方案3】:
      class User {
          constructor(public id: number, public name: string = null) {}
      }
      
      var USERS: User[] = [
          new User(1),
          new User(2, 'User 2')
      ];
      
      console.log(USERS);
      

      JsFiddle

      使用构造函数可能会让你的生活更轻松。当您尝试获取用户名时,您不会得到undefined,您将能够在类上定义函数。唯一的区别是您将使用 new User(...) 而不是仅使用对象字面量作为类型。

      【讨论】:

        猜你喜欢
        • 2017-12-23
        • 2015-12-30
        • 1970-01-01
        • 2017-07-28
        • 2017-02-26
        • 1970-01-01
        • 2016-07-31
        • 2018-08-15
        • 1970-01-01
        相关资源
        最近更新 更多