简单的示例按预期工作:
type Data = {
a: number
b: number
}
const data: Data[] = [
{a :1, b: 1},
{a: 2, b: 2}
].sort((el1, el2) => el1.a - el2.a)
排序工作,类型被保留。
但它不适用于元组数组:
type Data = [number, number]
const data: Data[] = [ // error: Type number[][] is not assignable to type Data[]
[1, 2],
[3, 4]
].sort((a, b) => a[0] - b[0])
对于异质物品,情况更糟:
type Data = [number, boolean]
const data: Data[] = [ // error: Type '(number | boolean)[][]' is not assignable to type 'Data[]'
[1, true],
[3, false]
].sort((a, b) => a[0] - b[0])
// ^? (parameter) a: (number | boolean)[]
我的类型在概念上是错误的吗?或者这是一个已知的限制,如果是,有解决方法吗?
我知道
.sort()
会改变数组。但由于顶级 不是 元组,我希望 TypeScript 保留结果类型并正确推断 .sort()
内部元素的类型。
为了
const data: Data[] = [[1, 2], [3, 4]].sort((a, b) => a[0] - b[0]);
要按原样工作,TypeScript 需要通过 contextually 将 Data[]
的预期返回类型传播回
通过对
sort()
的调用来推断 数组文字的类型,以便看到
[[1, 2], [3, 4]]
也必须是 Data[]
。 但上下文类型推断并不总是通过这种方式调用方法进行回溯。 这是语言的限制。类似的问题可以在 microsoft/Typescript#29771 和 microsoft/TypeScript#47440 中看到。
相反,
[[1, 2], [3, 4]]
最终会得到默认的非上下文推断类型number[][]
,然后sort()
返回number[][]
,并且赋值失败。
可以通过多种方式解决这个问题,所有这些方法都涉及开发人员指定更明确的类型,而不是依赖于推理。
我的建议是使用
[[1, 2], [3, 4]]
运算符: 为
Data[]
提供 satisfies
的上下文类型
const data: Data[] = ([
[1, 2],
[3, 4]
] satisfies Data[]).sort((a, b) => a[0] - b[0]) // okay
你也可以直接写
const data = ([
[1, 2],
[3, 4]
] satisfies Data[]).sort((a, b) => a[0] - b[0]) // okay
并且
data
的推断类型将等同于 Data[]
。这两个版本的优点是不更改运行时代码(加上或减去一些括号)并且相对类型安全(而不是使用 as
类型断言运算符)。