TypeScript中的可选参数是什么?

9

刚接触typescript,想知道在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;
  }

}
1个回答

20

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

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 基于结构子类型,而对此发出警告,两个类型共享相同的结构。但是,如果在 NavItem 中添加方法,很容易看出这是错误的:based on structural subtyping.
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"
})

你为什么没有建议为 NavItem 创建一个 constructor() 呢? - Zze
@Zze 我只是试图将更改最小化并专注于问题。此外,在这种情况下,以这种方式使用Object.assign是有意义的,而不是使用通常的样板构造函数,因为它除了将值分配给成员之外不会做任何其他事情。 - Nitzan Tomer
1
@Zze 请检查我的修订答案,我添加了一个使用 Object.assign 的构造函数。 - Nitzan Tomer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接