如何从属性名数组推导对应对象类型?
这个问题我之前也碰到过,其实核心是要让TypeScript捕获到你传入的具体键集合,而不是只把它当成宽泛的数组类型。我们一步步来解决:
首先,先回顾下你的基础类型定义:
interface StoredProps { location: boolean; notification: boolean; } type StorableKeys = keyof StoredProps;
你的原函数返回类型为{},是因为泛型T extends StorableKeys[]太宽泛了——TypeScript只会把T识别为“包含StorableKeys元素的数组”,不会记住你传入的具体键是什么。要让它推断出精确的返回类型,我们需要调整泛型约束和返回类型:
修正后的函数实现
const getStoredProps = <T extends readonly StorableKeys[]>(keys: T): { [K in T[number]]: StoredProps[K] } => { return keys.reduce((props, key) => { props[key] = storage.get(key); return props; }, {} as { [K in T[number]]: StoredProps[K] }); };
关键改动解释
泛型约束改为
T extends readonly StorableKeys[]
这样TypeScript会捕获你传入的数组的字面量类型,比如如果你传入['location', 'notification'],T就会被推断为readonly ['location', 'notification'],而不是模糊的StorableKeys[]。返回类型使用映射类型
{ [K in T[number]]: StoredProps[K] }是核心:T[number]会提取数组中所有元素的联合类型(比如'location' | 'notification')- 然后通过映射类型,把每个键
K对应到StoredProps[K]的具体类型,最终生成和传入键完全匹配的对象类型。
reduce初始值的类型断言
初始的{}类型太宽泛,我们用as { [K in T[number]]: StoredProps[K] }告诉TypeScript:我们最终会构建出这个类型的对象,避免类型报错。
使用示例
调用时TypeScript会自动推断出精确的返回类型:
// 返回类型自动推断为 { location: boolean; notification: boolean } const fullProps = getStoredProps(['location', 'notification']); // 返回类型自动推断为 { notification: boolean } const partialProps = getStoredProps(['notification']);
如果你不想用readonly约束,也可以保持泛型为T extends StorableKeys[],但调用时需要给数组加as const来让TypeScript捕获字面量类型:
const partialProps = getStoredProps(['notification'] as const);
这样就能完美实现“传入什么键,返回对应结构的类型”的需求了。
内容的提问来源于stack exchange,提问作者Explosion Pills

