TypeScript中Map泛型兼容及类构造器类型错误求助
TypeScript泛型类与Map类型的构造函数问题
我是TypeScript新手,尝试创建一个包含Map<string, Val<T>>类型属性的类,其中type Val<T> = string | number | Array<T>。编写构造函数时遇到以下问题:
- TypeScript要求必须声明
<T>,但Map中可能包含不同泛型参数T的数组 - 直接向构造函数传参会报错,但向类的
init方法直接传值能编译通过 - 若将参数存入变量再传入
init方法又会报错
类型定义
type Val<T> = string | number | Array<T>;
构造函数传参报错示例
export class MyClass<T> { model: Map<string, Val<T>>; constructor(model: [string, Val<T>][]) { this.model = new Map<string, Val<T>>(model); } } const c = new MyClass([ ["key1", "val1"], ["key2", 99], ["key3", ["cat", "dog"]], ["key4", [1,2,3]], ]);
错误信息
src/fakefuse.ts:38:15 - error TS2322: Type 'number' is not assignable to type 'string'. 38 ["key4", [1,2,3]], src/fakefuse.ts:38:17 - error TS2322: Type 'number' is not assignable to type 'string'. 38 ["key4", [1,2,3]], src/fakefuse.ts:38:19 - error TS2322: Type 'number' is not assignable to type 'string'. 38 ["key4", [1,2,3]],
init方法直接传参生效示例
class MyClass<T> { model: Map<string, Val<T>>; constructor() { this.model = new Map<string, Val<T>>(); } init(model: [string, Val<T>][]) { this.model = new Map<string, Val<T>>(model); } } const c = new MyClass(); c.init([ ["key1", "val1"], ["key2", 99], ["key3", ["cat", "dog"]], ["key4", [1,2,3]], ]);
变量传参给init报错示例
const c = new MyClass(); const aVar = [ ["key1", "val1"], ["key2", 99], ["key3", ["cat", "dog"]], ["key4", [1,2,3]], ]; c.init(aVar);
错误信息
src/fakefuse.ts:45:8 - error TS2345: Argument of type '((string | number)[] | (string | string[])[] | (string | number[])[])[]' is not assignable to parameter of type '[string, Val<unknown>][]'. Type '(string | number)[] | (string | string[])[] | (string | number[])[]' is not assignable to type '[string, Val<unknown>]'. Type '(string | number)[]' is not assignable to type '[string, Val<unknown>]'. Target requires 2 element(s) but source may have fewer. 45 c.init(aVar);
解决方案
问题核心在于原设计的类泛型<T>会强制所有Val<T>类型统一,而实际我们需要Map支持多种不同类型的Val值。以下是两种可行的实现方式:
方式1:使用非泛型的递归联合类型
直接定义支持所有允许值类型的Val,去掉类的泛型约束:
// 支持任意层级嵌套的Val类型 type Val = string | number | Val[]; class MyClass { model: Map<string, Val>; constructor(model: [string, Val][]) { this.model = new Map<string, Val>(model); } init(model: [string, Val][]) { this.model = new Map<string, Val>(model); } } // 构造函数直接传参 const c1 = new MyClass([ ["key1", "val1"], ["key2", 99], ["key3", ["cat", "dog"]], ["key4", [1,2,3]], ]); // 变量传参(可通过类型断言或const断言确保类型准确) const c2 = new MyClass([]); const aVar = [ ["key1", "val1"], ["key2", 99], ["key3", ["cat", "dog"]], ["key4", [1,2,3]], ] as [string, Val][]; c2.init(aVar);
方式2:使用泛型元组保留类型灵活性
通过泛型元组语法,让构造函数/init方法接受任意多类型的二元元组:
type Val<T> = T extends string | number ? T | T[] : never; class MyClass { model: Map<string, string | number | string[] | number[]>; constructor(model: [...[string, Val<any>][]]) { this.model = new Map(model); } init(model: [...[string, Val<any>][]]) { this.model = new Map(model); } } // 正常使用 const c = new MyClass([ ["key1", "val1"], ["key2", 99], ["key3", ["cat", "dog"]], ["key4", [1,2,3]], ]);
内容的提问来源于stack exchange,提问作者taffec
相关产品推荐
相关产品推荐

