繁体   English   中英

如何在 Map 中使用 `(K | V)[][]` 作为 `ReadonlyArray<[K, V]>`?

[英]How to use `(K | V)[][]` as `ReadonlyArray<[K, V]>` in a Map?

我想在 Map 构造函数中使用(K | V)[][]作为ReadonlyArray<[K, V]> 假设我们的 V 是一个接口IItem和 K 一个基本number

interface IItem {
    key: number;
    val: string;
}

const items = [[1, {key: 1, val: "a"}]] 
const ze_map = new Map<number, IItem>(items);
console.log(JSON.stringify([...ze_map]));

默认情况下,typescript 将感知项目类型为: (number | IItem)[][] 这将不起作用并引发错误:

'(number | { key: number; val: string; })[][]' 类型的参数不可分配给'ReadonlyArray<[{}, {}]>' 类型的参数。
类型 '(number | { key: number; val: string; })[]' 缺少来自类型 '[{}, {}]' 的以下属性:0, 1

幸运的是,我们可以强制类型为Array<[number, IItem]>来取悦Map

const items2 : Array<[number, IItem]> = [[1, {key: 1, val: "a"}]] 
const ze_map2 = new Map<number, IItem>(items2);
console.log(JSON.stringify([...ze_map]));

这项工作符合预期。 好吧,让我们转移到我的问题。 如果我们不能强制类型怎么办?

const arr = [
    { key: 3, val: 'bar' },
    { key: 5, val: 'world' }
];
const result: Array<[number, IItem]> = arr.map(i => ([i.key, i]));

const ze_map3 = new Map(result);
console.log(JSON.stringify([...ze_map]));

这不起作用,因为这里(number | { key: number; val: string; })[][]不是Array<[number, IItem]> 那么,如何在 Map 中将(K | V)[][]用作ReadonlyArray<[K, V]>

您可以在线尝试所有代码

我阅读了如何定义 Map 与键类型和值类型之间的相关性,虽然它们都是联合Typescript Map<enum, set<enum>> “没有重载匹配此调用”,但我不明白为什么? 没有找到解决方案。 我可能错过了解决方案。

我还阅读了Map 上的 MDN 条目,它说它应该按预期工作,如果你在 vanilla JS 中尝试它确实按预期工作:

var arr = [
    { key: 3, val: 'bar' },
    { key: 5, val: 'world' }
];

var result = arr.map(i => [i.key, i]);
const ze_map = new Map(result);

console.log(JSON.stringify([...ze_map])); 

在线尝试!

我觉得可能有更好的方法来实现这一点,但您可以通过在map例程中强制转换来强制类型:

const arr = [
    { key: 3, val: 'bar' },
    { key: 5, val: 'world' }
];
const result = arr.map(i => ([i.key, i] as [number, IItem])); // here come the trick
const ze_map3 = new Map(result);
console.log(JSON.stringify([...ze_map3]));

as关键字是一个类型断言,它告诉 tsc 将 object 视为另一种类型(即我们的[K, V] ),而不是编译器推断 object 的类型(即(K | V)[] )。

好消息是as [K, V]在 js output 中是完全透明的:

"use strict";
const arr = [
    { key: 3, val: 'bar' },
    { key: 5, val: 'world' }
];
const result = arr.map(i => [i.key, i]);
const ze_map3 = new Map(result);
console.log(JSON.stringify([...ze_map3]));

在线试用

资源

问题是.map回调的主体。 每当 function 返回一个数组时, Typescript 会将返回类型解释为普通数组类型而不是元组类型

避免as

as断言会起作用,但它可能很危险,因为它告诉 Typescript “即使它确实不是,也将这种类型视为[number, IItem] ”,而不是告诉 Typescript “我希望这种类型是[number, IItem]所以请确保它是。” 在您的情况下, as不是必需的,因为它确实是类型[number, IItem] 我们只需要让 typescript 以这种方式解释它。

设置泛型

最简单的方法是在.map function 上设置泛型类型参数。 此处的泛型变量设置回调的返回类型,因此我们将其设置为[number, IItem]

const result = arr.map<[number, IItem]>(i => [i.key, i]); // result has type [number, IItem][]

const ze_map = new Map(result); // no errors :)

外部化回调

另一种方法是将您的 map 回调i => [i.key, i]定义为它自己的 function 以便您可以注释返回类型。

const toTuple = (i: IItem): [number, IItem] => [i.key, i];

const result = arr.map(toTuple); // result has type [number, IItem][]

const ze_map = new Map(result); // no errors :)

Typescript 游乐场链接

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM