假设我有以下类型:
interface MyType {
myProperty: [a: string[], b: string[]]
}
现在我想创建一个该类型的数组:
const array1: MyType[] = [
{myProperty: [["Hello", "World"], []]},
{myProperty: [["Hello"], []]},
];
如果我尝试对该数组进行排序:
const array2: MyType[] = [
{myProperty: [["Hello", "World"], []]},
{myProperty: [["Hello"], []]},
].sort((a,b) => a.myProperty[0].length - b.myProperty[0].length);
我收到错误:
Type '{ myProperty: string[][]; }[]' is not assignable to type 'MyType[]'.
我尝试了各种解决方法:
使用排序(lambda)初始化数组
const array2: MyType[] = [
{myProperty: [["Hello", "World"], []]},
{myProperty: [["Hello"], []]},
].sort((a,b) => a.myProperty[0].length - b.myProperty[0].length);
值的类型不正确
使用排序(函数)初始化数组
const array3: MyType[] = [
{myProperty: [["Hello", "World"], []]},
{myProperty: [["Hello"], []]},
].sort(compareMyType);
function compareMyType(a: MyType, b: MyType) {
return a.myProperty[0].length - b.myProperty[0].length;
}
排序函数没有正确的类型,并且值没有正确的类型
投射到
MyType[]
:
const array4: MyType[] = ([
{myProperty: [["Hello", "World"], []]},
{myProperty: [["Hello"], []]},
] as MyType[]).sort(compareMyType);
const array5: MyType[] = ([
{myProperty: [["Hello", "World"], []]},
{myProperty: 5},
] as MyType[]).sort(compareMyType);
强制转换可以抑制可能导致运行时错误的错误
对已初始化的数组进行排序
const array1: MyType[] = [
const array2: MyType[] = [
{myProperty: [["Hello", "World"], []]},
{myProperty: [["Hello"], []]},
];
const array6: MyType[] = array1.sort(compareMyType);
没有错误。
为什么这个有效,而其他尝试却无效(编译器或运行时错误)?有更好/其他的解决方法吗?
问题在于 TypeScript 执行类型检查和类型推断的顺序。如果您只是将作业拆分并排序为两个单独的命令,则一切正常。
interface MyType {
myProperty: [a: string[], b: string[]]
}
const array1: MyType[] = [
{myProperty: [["Hello", "World"], []]},
{myProperty: [["Hello"], []]},
];
const array2: MyType[] = ([
{myProperty: [["Hello", "World"], []]},
{myProperty: [["Hello"], []]},
])
array2.sort((a,b) => a.myProperty[0].length - b.myProperty[0].length);
由于
sort
方法对数组进行就地排序,这完成了您所追求的目标。
问题是,在您的情况下,您正在对数组文字调用
sort
方法,因此 TS 必须独立于您指定的 array2
变量的类型来推断数组文字的类型,因为 sort
方法需要它正在排序的类型信息。只有在它尝试将排序数组的返回值分配给类型化的 array2
变量之后,才会发生不兼容性。
查看 TS 推断出该文字的内容并将其分配给无类型变量:
const array3 = ([
{myProperty: [["Hello", "World"], []]},
{myProperty: [["Hello"], []]},
])
// const array3: { myProperty: string[][]; }[]
如您所见,文字类型被推断为更简单的结构,
myProperty
字段不是元组,它只是被推断为常规字符串数组。但如果您单独执行分配,如我的示例所示,TS 将对文字进行更精细的检查,并确保它与请求的类型匹配。
绊脚石是 TypeScript 的默认行为是将数组文字的类型推断为普通数组类型,而不是元组。 TypeScript 的 上下文打字 通常不能通过函数调用来工作,因此,虽然
const arr: MyType[] = [⋯]
将拥有正确的上下文以使其成功,但 const arr: MyType[] = [⋯].sort(⋯)
则不会。
satisfies
运算符而不是类型断言:
const arr: MyType[] = ([
{myProperty: [["Hello", "World"], []]},
{myProperty: [["Hello"], []]},
] satisfies MyType[]).sort(compareMyType);
您可以使用
satisfies
为类型推断提供上下文,而不会失去类型安全性。