這是問題的簡化版本。我正在嘗試創建一個函式,該函式將在具有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的值型別。
uj5u.com熱心網友回復:
使用物件而不是 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);
操場
uj5u.com熱心網友回復:
您可以使用一些條件型別來推斷地圖的鍵和值型別。呼叫時會遇到型別問題,set因為 TS 推斷d[dataKey]為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.
這里還有一個到操場的鏈接。
uj5u.com熱心網友回復:
在推理的幫助下是可以做到的。您應該推斷整個資料結構。從Map關鍵開始。
interface Dictionary {
map1: Map<string, number>;
map2: Map<string, string>;
}
const d: Dictionary = {
map1: new Map(),
map2: new Map(),
};
type InferMap<T extends Map<any, any>> = T extends Map<infer Key, infer Value> ? [Key, Value] : never
// This doesn't work
const dataSet = <
Key extends string,
Value extends string | number,
HashMapKey extends string,
HashMap extends Record<HashMapKey, Map<Key, Value>>,
>(hashMap: HashMap, dataKey: HashMapKey) =>
(key: InferMap<HashMap[HashMapKey]>[0], val: InferMap<HashMap[HashMapKey]>[1]) =>
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 - 推斷整個資料結構(引數)
InferMap- 推斷映射鍵和映射值并回傳元組,其中第一個元素是鍵,第二個元素是值。
操場
如果你對函式引數推斷感興趣,可以查看我的文章
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/317362.html
