typescript 打字稿中的可选参数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/43730579/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 04:30:13  来源:igfitidea点击:

optional parameters in typescript?

typescript

提问by Richard G

Just new to typescript in an angular context. Can you mark properties as optional in the example below? How would you recommend specifying a nav item has no children? With regular JS I would usually rely on a falsey value to check if the object has childrenproperty. But in Typescript is it best practice to initialise an empty array? What about other primitive properties that may/may not have values?

在角度上下文中刚刚接触打字稿。您可以在下面的示例中将属性标记为可选吗?您如何建议指定没有子项的导航项?使用常规 JS,我通常会依靠 falsey 值来检查对象是否具有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;
  }

}

回答by Nitzan Tomer

Yeah, it's very easy to mark a property as optional, you add ?after it:

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

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

Alternatively you can also use a union with nullor undefined:

或者,您也可以使用带有null或的联合undefined

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

With that being said, you misunderstood something very important, this is wrong:

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

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

datais notan array of NavItemitems, in order to get that you'll need to create instances of NavItemusing the newkeyword, for example:

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

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

The compiler doesn't complain about doing that because typescript is based on structural subtypingand the two types share the same structure.
But it's easy to see why it's wrong by adding methods to NavItem:

编译器不会抱怨这样做,因为打字稿基于结构子类型,并且这两种类型共享相同的结构。
但是通过向以下添加方法很容易看出为什么它是错误的NavItem

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

  getKey() {
    return this.key;
  }
}

Now try this with your code:

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

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

And you'll end up with:

你最终会得到:

Uncaught TypeError: data[0].getKey is not a function

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

You should even get a compilation error saying that getKeyis missing in your array items.

您甚至应该收到一个编译错误,说明getKey您的数组项中缺少该错误。

If you only intend to use NavItemas data objects then it doesn't really matter, but you should just use interfaces or type aliases instead as they don't get compiled to js and you avoid redundant memory usage:

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

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


Edit

编辑

After a comment from @Zze I've decided to add a simple constructor that uses the "power" of Object.assign:

在@Zze 发表评论后,我决定添加一个简单的构造函数,该构造函数使用以下“功能” Object.assign

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

  constructor(data?: NavItem) {
      if (data) {
          Object.assign(this, data);
      }
  }
}

then:

然后:

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