美文网首页
TypeScript 中的数组类型

TypeScript 中的数组类型

作者: 涅槃快乐是金 | 来源:发表于2024-03-25 13:31 被阅读0次

TS的数组类型你使用哪个?Array<string>(泛型语法)与 string[](数组语法),这两种表示法在功能上完全没有区别。但其中总是涉及细微差别和权衡。通常情况下,泛型表示法要好得多。
关于这个问题时,一起分析下两种写法的不足和优势

数组语法更短

就是这样。这就是优势所在。写入的字符更少。好像代码越短就越易维护一样。
但我们更经常阅读代码而不是编写它,因此我们不应该专注于使其易于编写——它应该易于阅读。

泛型语法可读性

我们通常从左到右阅读,所以更重要的东西应该先出现。我们说:“这是一个字符串数组”,或者“这是一个字符串或数字数组”。

//从左到右
// ✅ 从左到右阅读起来很舒服
function add(items: Array<string>, newItem: string)

// ❌ 看起来与“string”非常相似
function add(items: string[], newItem: string)

如果我们数组中的类型是相当长的,则这一点尤为重要,例如因为它是从某处推断出来的。IDE 通常以数组表示法显示数组类型,所以有时,当我悬停在一个对象数组上时,我会得到这样的内容:

//options-array
const options: {
  [key: string]: unknown
}[]

这读起来像是 options 是一个对象,只有在最后,我才能看到它实际上是一个数组。如果对象有很多属性,情况就会变得更糟,因为这会使内容变得更长,并且会给浮动框增加一个滚动条——使得很难看到最后的 []。诚然,这可能是一个工具问题,但如果我们将其显示为它的本质:一个对象数组,这个问题就不存在了。当跨多行展示时,它甚至不会长得多:

//array-of-options
const options: Array<{
  [key: string]: unknown
}>

不管怎样,我们继续往下看,因为这不是数组表示法的唯一优点。

ReadonlyArray

让我们面对现实——我们作为函数输入的大多数数组都应该是只读的,以避免意外的突变。我也在另一篇文章中提到了这个话题。如果你使用泛型表示法,你可以简单地将Array替换为ReadonlyArray并继续前进。如果你使用数组表示法,你必须将它拆分成两部分:

## readonly-arrays
// ✅ 最好使用 readonly,这样你不会意外改变 items
function add(items: ReadonlyArray<string>, newItem: string)

// ❌ "readonly" 和 "Array" 现在被分开了
function add(items: readonly string[], newItem: string)

这并不是什么大不了的事,但 readonly 是一个只能用于数组和元组的保留字,在我们有一个内置的实用类型可以完成同样工作时,这确实很奇怪。而将 readonly[]拆分开真的会在阅读时影响流畅性。

Union types

如果我们扩展我们的add函数,使其也接受数字——因此我们想要一个字符串或数字的数组。使用泛型表示法不会有问题:

//array-of-unions
// ✅ 和以前完全一样
function add(items: Array<string | number>, newItem: string | number)

然而,如果使用数组表示法,情况开始变得奇怪

//string-or-number-array
// ❌ 看起来还行,但实际不是
function add(items: string | number[], newItem: string | number)

如果你无法立即发现错误——那就是问题的一部分。它隐藏得如此之深,以至于需要一些时间才能看到。让我们通过实际实现该函数并查看我们收到的错误来帮助一下:

//not-assignable
// ❌ 为什么这不起作用 😭
function add(items: string | number[], newItem: string | number) {
  return items.concat(newItem)
}

显示以下错误:

Type 'string' is not assignable to type 'ConcatArray<number> & string' (2769)
TypeScript playground

对我来说,这一点毫无意义。为了解决这个谜题:这涉及到运算符优先级。[] 的绑定强度比 | 运算符更强,所以现在我们已经使 items 成为了 string OR number[] 类型。

我们想要的是:(string | number)[],带括号,以使我们的代码正常工作。泛型版本没有这个问题,因为它无论如何都会使用尖括号将 Array 与其内容分开。

keyof

让我们看一个相当常见的例子,我们有一个函数接受一个对象,并且我们还想将此对象的可能键的数组传递给同一个函数。如果我们想要实现类似 pickomit的函数,我们就需要这个:

//pick
const myObject = {
  foo: true,
  bar: 1,
  baz: 'hello world',
}

pick(myObject, ['foo', 'bar'])

我们只想允许现有键作为第二个参数传递,那么我们该怎么做呢?使用 keyof类型操作符:

//pick-generic-notation
function pick<TObject extends Record<string, unknown>>(
  object: TObject,
  keys: Array<keyof TObject>
)

当我们使用泛型语法为数组时,一切都正常。但是如果我们将其更改为数组语法会发生什么?

//pick-array-notation
function pick<TObject extends Record<string, unknown>>(
  object: TObject,
  keys: keyof TObject[]
)

令人惊讶的是,没有错误,所以这应该是正确的。没有错误甚至更糟,因为这里存在错误——它只是不会显示在函数声明中——而是在我们尝试调用它时出现:

pick(myObject, ['foo', 'bar'])

现在产生:

Argument of type 'string[]' is not assignable to parameter of type 'keyof TObject[]'.(2345)

这条消息比之前的消息更加让人摸不着头脑。为什么我的键不是字符串?不知道 keyof TObject[]的合法输入是什么。只知道定义我们想要的正确方式是:(keyof TObject)[]

//fixed-array-notation
function pick<TObject extends Record<string, unknown>>(
  object: TObject,
  keys: (keyof TObject)[]
)

这些都是我在使用数组表示法时遇到的问题。

相关文章

  • TypeScript入门基础(数组类型、函数类型)

    数组的类型 在 TypeScript 中,数组类型有多种定义方式,比较灵活。 「类型 + 方括号」表示法 数组的项...

  • TypeScript基础三(数组类型、函数类型)

    数组类型 在 TypeScript 中,数组类型有多种定义方式,比较灵活。 「类型 + 方括号」表示法 numbe...

  • TypeScript 入门教程 — 数组的类型

    在 TypeScript 中,数组类型有多种定义方式,比较灵活。 「类型 + 方括号」表示法: 数组的项中不允许出...

  • TypeScript类型

    TypeScript类型 基础类型 string number boolean 数组 两种定义数组方法: 对象类型...

  • TypeScript 数组类型

    和 JavaScript 语言一样,TypeScript 中也有数组类型。 数组指的是有序的元素序列,例如 [1,...

  • TypeScript 数组类型

    和 JavaScript 语言一样,TypeScript 中也有数组类型。 数组指的是有序的元素序列,例如 [1,...

  • 数组和元组

    TypeScript里如何对数组和元组进行类型注解 TypeScript 里的数组,实际上和JS里的数组完全是一样...

  • TypeScript简单入门(八):TypeScript数组的类

    在 TypeScript 中,数组类型有多种定义方式,比较灵活。「类型 + 方括号」表示法 最简单的方法是使用「类...

  • 数据类型

    typescript 命令 ​ tsc --init 生成配置文件 ts的基础数据类型 特殊数据类型 数组 ...

  • 5. 使用TypeScript

    在本章中,我们将讨论: Deno中的TypeScript概述。在Deno中配置TypeScript。类型和类型声明...

网友评论

      本文标题:TypeScript 中的数组类型

      本文链接:https://www.haomeiwen.com/subject/qpvdtjtx.html