排序改变数组类型

问题描述 投票:0回答:2

假设我有以下类型:

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
2个回答
0
投票

问题在于 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 将对文字进行更精细的检查,并确保它与请求的类型匹配。


0
投票

绊脚石是 TypeScript 的默认行为是将数组文字的类型推断为普通数组类型,而不是元组。 TypeScript 的 上下文打字 通常不能通过函数调用来工作,因此,虽然

const arr: MyType[] = [⋯]
将拥有正确的上下文以使其成功,但
const arr: MyType[] = [⋯].sort(⋯)
则不会。

继续这里的最佳方法可能是使用

satisfies
运算符而不是类型断言

const arr: MyType[] = ([
    {myProperty: [["Hello", "World"], []]},
    {myProperty: [["Hello"], []]},
] satisfies MyType[]).sort(compareMyType);

您可以使用

satisfies
为类型推断提供上下文,而不会失去类型安全性。

Playground 代码链接

© www.soinside.com 2019 - 2024. All rights reserved.