【问题标题】:Typescript types for empty map and array空地图和数组的打字稿类型
【发布时间】:2017-09-28 19:50:07
【问题描述】:

在打字稿中,我如何表达一个函数只接受一个空映射或数组?

类似这样的东西(但它不起作用):

function foo(emptyMapOrArray: {} | []) {
    //...
}

// This should error
foo(["a"])
foo({a: 1})
// This should work
foo([])
foo({})

用例是我希望能够将“原子”值分配给 JSON 文档的一部分。类似于 paper 中使用的光标。所以一个更完整的例子是这样的:

function assign(map: {}, key: string, value: string | number | boolean | {} | []) {
  map[key] = value
}

但是我意识到我可以将空映射和空数组建模为单独的操作。但我仍然认为了解 typescript 中的类型系统在这种情况下的表现力是多么有趣。

【问题讨论】:

  • 你的用例是什么?
  • 用用例更新

标签: typescript


【解决方案1】:

就像 Paleo 所说,您可以使用 { [index: string]: never } 检查空对象。

但是,TypeScript 只能强制您放入数组中的元素的类型,它不能为您检查数组的长度,因此您的问题的第二部分对于 TypeScript 是不可能的。

This issue on GitHub 上面有一些 cmets(强调我的):

  • 我们的观点是,元组是一个数组,我们对前 N 个元素的各个类型有静态知识,并且元素类型是这 N 个元素的类型的并集。我们允许存在 N 个以上的元素(因为我们确实无法禁止它),但我们确实要求这些元素具有兼容的类型。

  • 当意识到没有检查数组元素的数量时,元组功能似乎不像我第一印象那样有吸引力。

  • 元组基本上是具有数字属性的对象。所以foo: [string, string] 就像说foo: {0: string, 1: string}

  • 根据规范第 3.3.3 节,[number, string] 类型等价于扩展 Array 的接口: interface NSPair extends Array<number | string> { 0: number, 1: string }

如果你尝试实现一个类似后者的接口,你会得到一个错误:

interface EmptyArray extends Array<any> { 0: never; }
const doesntWork: EmptyArray = [];

给出的错误是TS2322: Type 'undefined[]' is not assignable to type 'EmptyArray'. Property '0' is missing in type 'undefined[]'.

如果你尝试extends Array&lt;never&gt;,错误是一样的。基本上无论你如何试图争论定义,你都会得到错误。

我的理解是.length 是一个运行时属性。 TypeScript 必须运行你的代码来检查它,这是它做不到的。

【讨论】:

  • 你确定它不能检查一般数组的长度吗?我的印象是它对元组类型(例如[string, number])执行此操作。
  • @JonasKello,见编辑。更新了答案,因为评论会很长。
【解决方案2】:

使用选项--strictNullChecks

我建议:

function foo(emptyMapOrArray: { [index: string]: never } | never[]) {
    //...
}

注意:此代码需要编译器选项strictNullChecks。否则,foo([]) 语句将无法编译。

没有选项--strictNullChecks

如果没有编译器选项strictNullChecks,您可能更喜欢:

function foo(emptyMapOrArray: { [index: string]: never } | undefined[]) {
    //...
}

但这并不完美:

foo([undefined]) // no error here, but it should!

【讨论】:

  • 谢谢,巧妙地使用了never 类型,我没想到:-)。
  • 为什么使用undefined[] 而不是never[]
  • @csander 因为使用never[],调用foo([]) 无法编译。
  • 对我来说很好:function a(b: never[]) { console.log(b) }; a([])
  • @csander 没错!它适用于编译器选项strictNullChecks。我编辑了我的答案。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-12
  • 2019-09-01
  • 1970-01-01
  • 2017-02-20
  • 1970-01-01
相关资源
最近更新 更多