【问题标题】:optional parameters in typescript?打字稿中的可选参数?
【发布时间】:2017-05-02 13:46:47
【问题描述】:

在 Angular 上下文中刚接触打字稿。您可以在下面的示例中将属性标记为可选吗?您如何建议指定导航项没有子项?对于常规的 JS,我通常会依靠一个虚假的值来检查对象是否具有 children 属性。但是在 Typescript 中,最好的做法是初始化一个空数组吗?那么其他可能/可能没有值的原始属性呢?

import { Injectable } from '@angular/core';

export class NavItem {
  key: string;
  text: string;
  target: string;
  children: NavItem[];
}

const data: NavItem[] = [
  {
    key: "dashboard",
    target: "dashboard",
    text: "Dashboard",
    children: []
  },
  {
    key: "sales",
    target: "sales",
    text: "Sales"
  }
];

@Injectable()
export class NavService {
  getNav() {
    return data;
  }

}

【问题讨论】:

    标签: typescript


    【解决方案1】:

    是的,将属性标记为可选非常容易,您可以在其后添加?

    class NavItem {
      key: string;
      text: string;
      target: string;
      children?: NavItem[];
    }
    

    或者,您也可以使用nullundefined 的联合:

    class NavItem {
      key: string;
      text: string;
      target: string;
      children: NavItem[] | undefined;
    }
    

    话虽如此,您误解了一些非常重要的事情,这是错误的:

    const data: NavItem[] = [
      {
        key: "dashboard",
        target: "dashboard",
        text: "Dashboard",
        children: []
      },
      {
        key: "sales",
        target: "sales",
        text: "Sales"
      }
    ];
    

    data不是 NavItem 项目的数组,为了得到你需要使用new 关键字创建NavItem 的实例,例如:

    const data: NavItem[] = [
      Object.assign(new NavItem(), {
        key: "dashboard",
        target: "dashboard",
        text: "Dashboard",
        children: []
      }),
      Object.assign(new NavItem(), {
        key: "sales",
        target: "sales",
        text: "Sales"
      })
    ];
    

    编译器不会抱怨这样做,因为 typescript 是 based on structural subtyping 并且这两种类型共享相同的结构。
    但是给NavItem添加方法就很容易看出为什么不对了:

    class NavItem {
      key: string;
      text: string;
      target: string;
      children?: NavItem[];
    
      getKey() {
        return this.key;
      }
    }
    

    现在用你的代码试试这个:

    console.log(data[0].getKey());
    

    你最终会得到:

    未捕获的类型错误:data[0].getKey 不是函数

    您甚至应该得到一个编译错误,指出您的数组项中缺少getKey

    如果您只打算使用NavItem 作为数据对象,那么这并不重要,但您应该只使用接口或类型别名,因为它们不会被编译为 js,并且您可以避免多余的内存使用:

    interface NavItem {
      key: string;
      text: string;
      target: string;
      children?: NavItem[];
    }
    

    编辑

    在@Zze 发表评论后,我决定添加一个简单的构造函数,它使用Object.assign 的“力量”:

    class NavItem {
      key: string;
      text: string;
      target: string;
      children?: NavItem[];
    
      constructor(data?: NavItem) {
          if (data) {
              Object.assign(this, data);
          }
      }
    }
    

    然后:

    new NavItem({
        key: "sales",
        target: "sales",
        text: "Sales"
    })
    

    【讨论】:

    • 您是否有理由不建议为constructor() 创建NavItem
    • @Zze 只是试图将其保持在最低限度的变化并专注于问题。此外,在这种情况下,以这种方式使用 Object.assign 而不是使用通常的样板构造函数是有意义的,因为除了为成员分配值之外它不会做任何事情。
    • @Zze 检查我修改后的答案,我添加了一个使用 Object.assign 的构造函数
    猜你喜欢
    • 2020-05-22
    • 1970-01-01
    • 2018-08-05
    • 1970-01-01
    • 1970-01-01
    • 2022-11-16
    • 2021-05-18
    • 1970-01-01
    • 2021-05-03
    相关资源
    最近更新 更多