You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何限制泛型参数实现单属性对象动态创建工厂函数?

问题描述

我想编写一个工厂函数来创建对象实例,生成的对象仅包含一个属性,但属性名称和对应值的类型需要动态指定(属性名用常量指定即可)。目标是创建属性为单元素数组的对象,我尝试使用泛型与类型约束,但未完全掌握其用法。

原代码如下:

// 目标:创建一个属性为单元素数组的对象
function factory<TContainer, TElement>(key: string, element: TElement): TContainer {
    return {[key]: [element]};
}

期望的使用方式:

// 期望用法

// 给定一个类型
type T1 = {
    key1: number[];
};

// 替代这种写法
const e1a: T1 = { key1: [1]};
const e1b: T1 = { key1: [1, 2]};
const e1c: T1 = { key1: []};

// 我想这么写
const e1z: T1 = factory<T1, number>('key1', 999); // e1z === {key1: [999]};
const e2z: T2 = factory<T2, string>('key2', 'z'); // e2z === {key2: ['z']};

// 另外也想不用显式类型的写法
const onthefly:{onthefly:string[]} = factory<{onthefly:string[]}, string>('onthefly', 'onthefly'); // onthefly === {onthefly: ['onthefly']};

// 更理想的是编译器能自动推断类型,不用我指定
const magic = factory('magic', 3); // magic:{magic:number[]} === {magic:[3]}

但运行时出现错误:

Type '{ [x: string]: TElement[]; }' is not assignable to type 'TContainer'.
      'TContainer' could be instantiated with an arbitrary type which could be unrelated to '{ [x: string]: TElement[]; }'.
解决方案

问题核心在于原泛型的约束过于松散,TContainer可以是任意类型,TypeScript无法确认返回的对象与TContainer结构匹配。我们需要调整泛型参数,让类型之间建立明确的关联。

方案1:自动推断属性名与元素类型

使用两个泛型参数:K约束为字符串字面量类型(代表属性名),T代表元素类型。返回值类型明确为仅包含该属性的对象,属性值为单元素数组:

function factory<K extends string, T>(key: K, element: T): { [P in K]: T[] } {
    return { [key]: [element] } as { [P in K]: T[] };
}

验证期望用法:

  1. 针对预定义类型:
type T1 = { key1: number[] };
const e1z: T1 = factory('key1', 999); // 类型匹配,无错误

type T2 = { key2: string[] };
const e2z: T2 = factory('key2', 'z'); // 正常工作
  1. 即时定义类型:
const onthefly: { onthefly: string[] } = factory('onthefly', 'onthefly'); // 符合预期
  1. 自动推断类型:
const magic = factory('magic', 3); // 自动推断出 magic 的类型是 { magic: number[] }

方案2:支持显式指定目标容器类型

如果你需要显式指定目标容器类型,可以调整泛型,让TContainer约束为包含单个属性的对象,同时关联属性名和元素类型:

function factory<TContainer extends Record<K, T[]>, K extends string, T>(key: K, element: T): TContainer {
    return { [key]: [element] } as unknown as TContainer;
}

用法示例:

type T1 = { key1: number[] };
// 显式指定所有泛型参数
const e1z = factory<T1, 'key1', number>('key1', 999);
// 利用类型推断,仅指定TContainer
const e1z2 = factory<T1>(('key1' as const), 999);

原代码报错原因

原代码中TContainer没有任何约束,TypeScript无法保证返回的{ [key]: [element] }与TContainer结构一致。比如若有人调用factory<number, string>('key', 'val'),返回的对象显然不是number类型,因此编译器会报错。通过给泛型添加约束,让类型之间建立关联,即可解决该问题。

内容的提问来源于stack exchange,提问作者Vito De Tullio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 21:30:55