[英]Typescript: Generic over Map<K,V> value type
这是问题的简化版本。 我正在尝试创建一个函数,该函数将在具有Map
属性的接口上进行通用操作。
interface Data {
map1: Map<string, number>;
map2: Map<string, string>;
}
const d: Data = {
map1: new Map(),
map2: new Map(),
};
// This doesn't work
public dataSet<T extends keyof Data, V extends Data[T]... (need help here)>(d: data, dataKey: T, key: string, val: V) {
d[dataKey].set(key, val);
}
// Ideally, called like:
dataSet(d, 'map1', 'alpha', 3);
dataSet(d, 'map2', 'beta', 'charlie');
V
的类型定义目前是Map
类型而不是Map
的值类型。
使用对象而不是 Maps 怎么样?
interface Data {
map1: {
[K: string]: number
};
map2: {
[K: string]: string
};
}
const d: Data = {
map1: {},
map2: {},
};
function dataSet<T extends keyof Data, V extends Data[T][string]>(d: Data, dataKey: T, key: string, val: V) {
d[dataKey][key] = val;
}
// works:
dataSet(d, 'map1', 'alpha', 3);
dataSet(d, 'map2', 'beta', 'charlie');
// Errors
dataSet(d, 'map1', 'alpha', 'charlice');
dataSet(d, 'map2', 'beta', 3);
您可以使用一些条件类型来推断地图的键和值类型。 调用set
时会遇到类型问题,因为 TS 将d[dataKey]
推断为Map<string, number> | Map<string, string>
Map<string, number> | Map<string, string>
。 但是我们知道我们在这里做什么,所以我们可以安全地添加@ts-expect-error
行。
我在操场上的 TS v4.1.5 上对此进行了测试。
interface Data {
map1: Map<string, number>;
map2: Map<string, string>;
}
const d: Data = {
map1: new Map(),
map2: new Map(),
};
type GetKey<M extends Map<any, any>> = M extends Map<infer K, any> ? K : never;
type GetValue<M extends Map<any, any>> = M extends Map<any, infer V> ? V : never;
function dataSet<K extends keyof Data>(d: Data, dataKey: K, key: GetKey<Data[K]>, val: GetValue<Data[K]>) {
// @ts-expect-error
d[dataKey].set(key, val);
}
// This now enforces the types correctly.
dataSet(d, 'map1', 'alpha', 3);
dataSet(d, 'map2', 'beta', 'charlie');
dataSet(d, 'map2', 'foo', true); // Errors as expected.
更新
在推理的帮助下是可以做到的。 您应该推断整个数据结构。
interface Dictionary {
map1: Map<string, number>;
map2: Map<string, string>;
}
const d: Dictionary = {
map1: new Map(),
map2: new Map(),
};
const dataSet = <
MapKey,
MapValue,
HashMapKey extends string,
HashMap extends Record<HashMapKey, Map<MapKey, MapValue>>,
>(hashMap: HashMap, dataKey: HashMapKey, key: MapKey, val: MapValue) =>
hashMap[dataKey].set(key, val);
// Ideally, called like:
dataSet(d, 'map1', 'alpha', 2) // ok
dataSet(d, 'map1', 'alpha', 'str') // expected error
dataSet(d, 'map2', 'beta', 'charlie');
dataSet(d, 'map2', 'beta', 4); // expected error
HashMapKey
- 推断map1
和map2
HashMap
- 推断整个数据结构(参数)
如果你对函数参数推断感兴趣,可以查看我的文章
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.