使用Typescript在数组上使用`map`返回一个元组数组。

huangapple go评论72阅读模式
英文:

returning an Array of tuples using map on an Array in Typescript

问题

I have an Array const x:number[] = [1,2,3,4,5] and I'm trying to obtain an array of tuples containing the original value in x and a value obtained by mapping a function on it.
我的目标是获取一个包含 x 中原始值和映射函数产生的值的元组数组。

My attempt was something like this
我的尝试是类似这样的:

pos = x.map(xi => (
    [xi, 3*xi]
))

This returns pos as of type number[][] but I want a [number, number] as result.
这会将 pos 返回为 number[][] 类型,但我想要的是 [number, number] 作为结果。

Do you know how to fix this code?
你知道如何修复这段代码吗?

英文:

I have an Array const x:number[] = [1,2,3,4,5] and I'm trying to obtain an array of tuples containing the original value in x and a value obtained by mapping a function on it.
My attempt was something like this

pos = x.map(xi => (
    [xi, 3*xi]
))

This returns pos as of type number[][] but I want a [number, number] as result.
Do you know how to fix this code?

答案1

得分: 1

默认情况下,TypeScript 会将像 [xi, 3 * xi] 这样的 数组字面量 推断为无序的 数组类型,长度可以是任意的,比如 number[],而不是 元组类型,比如 [number, number]。 这通常是人们所期望的,因为数组比元组更常见。 当这种推断不合适时,您需要采取措施来告诉编译器要做其他的事情。

有多种方法可以实现这一点。 如果您明确想要 [number, number],那么最直接的方法是为 Array.prototype.map 方法 手动指定 U 类型参数,该方法的声明如下(在这里声明):

interface Array<T> {
    map<U>(cb: (v: T, i: number, a: T[]) => U, thisArg?: any): U[];
}

像这样:

const x: number[] = [1, 2, 3, 4, 5];
const pos = x.map<[number, number]>(xi => (
   [xi, 3 * xi]
));
// const pos: [number, number][]

但通常情况下,您可以要么手动注释分配字面值的变量:

const pos = x.map(xi => {
   const ret: [number, number] = [xi, 3 * xi];
   return ret;
});
// const pos: [number, number][]

要么您可以使用 const 断言 来让编译器改变其推断算法,以更喜欢字面类型readonly 元组

const pos = x.map(xi => [xi, 3 * xi] as const);
// const pos: (readonly [number, number])[]

readonly [number, number] 类型与 [number, number] 不完全相同,但根据您的用例,它可能足够了。

英文:

By default, TypeScript will see an array literal like [xi, 3 * xi] and infer its type to be an unordered array type of arbitrary length like number[], and not a tuple type like [number, number]. That's often what people want, since arrays are more common than tuples. When such inference isn't suitable, you'll need to do something to ask the compiler to do something else.

There are a number of ways to do this. If you explicitly want [number, number], then the most straightforward approach is to manually specify the U type argument for the Array.prototype.map method which is declared like:

interface Array&lt;T&gt; {
    map&lt;U&gt;(cb: (v: T, i: number, a: T[]) =&gt; U, thisArg?: any): U[];
}

Like this:

const x: number[] = [1, 2, 3, 4, 5];
const pos = x.map&lt;[number, number]&gt;(xi =&gt; (
   [xi, 3 * xi]
));
// const pos: [number, number][]

But in general, you can either manually annotate the variable to which you're assigning the literal:

const pos = x.map(xi =&gt; {
   const ret: [number, number] = [xi, 3 * xi];
   return ret;
});
// const pos: [number, number][]

or you could use a const assertion to get the compiler to change its inference algorithm to prefer literal types and readonly tuples:

const pos = x.map(xi =&gt; [xi, 3 * xi] as const);
// const pos: (readonly [number, number])[]

The type readonly [number, number] is not identical to [number, number], but depending on your use case it might suffice.

Playground link to code

huangapple
  • 本文由 发表于 2023年3月21日 01:42:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/75793581.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定