TypeScript中基于键值元组生成CachedItems类型的实现疑问
TypeScript中基于键值元组生成CachedItems类型的实现疑问
你这个需求完全可以实现!先说说你之前写法的问题所在,再给你正确的实现思路~
为什么你的原写法没生效?
你原来的代码是先遍历元组索引生成数组类型,每个元素是单个键的Record,最后用[number]取出联合类型。但联合类型的对象意味着要么包含users,要么包含blacklist,要么包含something,而不是同时拥有所有键的完整对象——这就是为什么你要么报错,要么得到never类型的原因。
正确的实现方式
从TypeScript 4.1版本开始,我们可以利用**映射类型的键重映射(as关键字)**来完美实现这个需求。核心思路是遍历元组的索引,把每个索引对应的键(T[I])作为对象的属性名,同时取出对应位置的值类型(V[I])构建Map<string, V[I]>。
简洁版实现(推荐)
// 定义测试用的基础类型 type User = { id: string; name: string } type Blacklist = { userId: string; reason: string } type Something = { data: any } // 核心类型实现 type CachedItems<T extends readonly string[], V extends readonly any[]> = { [I in keyof T as T[I]]: Map<string, V[I]> };
测试验证
// 生成目标类型 type Result = CachedItems<['users', 'blacklist', 'something'], [User, Blacklist, Something]>; /* Result最终的类型完全符合你的预期: { users: Map<string, User>; blacklist: Map<string, Blacklist>; something: Map<string, Something>; } */
可选:强制元组长度一致
如果你想避免因为两个元组长度不匹配导致的潜在问题,可以给类型加上更严格的约束,强制T和V的长度必须相等:
type CachedItems< T extends readonly string[] & { length: V['length'] }, V extends readonly any[] > = { [I in keyof T as T[I]]: Map<string, V[I]> };
这样如果传入的两个元组长度不一样,TypeScript会直接抛出错误,提前规避问题。
备注:内容来源于stack exchange,提问作者shadowplay1
相关产品推荐
相关产品推荐

