如何为TypeScript的createProduct函数实现输入输出类型映射?
实现输入输出的类型映射
要让createProduct根据传入的具体Spec子类型返回对应的Product子类型,可以通过以下两种方式实现:
方法一:泛型结合条件类型
先定义基础类型,再通过泛型约束和条件类型建立输入到输出的映射关系:
// 定义具体的Spec子类型 type SpecA = { type: 'a'; aProp: string }; type SpecB = { type: 'b'; bProp: number }; // 区分联合类型 type Spec = SpecA | SpecB; // 对应Product子类型 type ProductA = { type: 'a'; productAData: string }; type ProductB = { type: 'b'; productBData: number }; // 泛型函数,通过条件类型映射返回值 function createProduct<T extends Spec>(spec: T): T extends SpecA ? ProductA : ProductB { if (spec.type === 'a') { return { type: 'a', productAData: spec.aProp } as T extends SpecA ? ProductA : ProductB; } else { return { type: 'b', productBData: spec.bProp } as T extends SpecA ? ProductA : ProductB; } } // 调用示例:返回类型被推断为ProductA const productA = createProduct({ type: 'a', aProp: 'demo' }); // 调用示例:返回类型被推断为ProductB const productB = createProduct({ type: 'b', bProp: 123 });
这种方式利用TypeScript的条件类型,让泛型T对应传入的具体Spec子类型,进而返回匹配的Product子类型。
方法二:函数重载
通过定义函数重载签名,明确不同输入对应的输出类型:
// 定义基础类型(同方法一) type SpecA = { type: 'a'; aProp: string }; type SpecB = { type: 'b'; bProp: number }; type Spec = SpecA | SpecB; type ProductA = { type: 'a'; productAData: string }; type ProductB = { type: 'b'; productBData: number }; // 重载签名:明确输入输出的对应关系 function createProduct(spec: SpecA): ProductA; function createProduct(spec: SpecB): ProductB; // 实现签名:处理联合类型的逻辑 function createProduct(spec: Spec) { if (spec.type === 'a') { return { type: 'a', productAData: spec.aProp }; } else { return { type: 'b', productBData: spec.bProp }; } } // 调用示例:返回类型推断为ProductA const productA = createProduct({ type: 'a', aProp: 'demo' }); // 调用示例:返回类型推断为ProductB const productB = createProduct({ type: 'b', bProp: 123 });
函数重载通过多个签名声明不同的输入输出组合,TypeScript会根据传入的字面量参数匹配对应的重载,返回精确的类型。
注意事项
如果传入的是类型为Spec的变量(而非字面量),比如:
const spec: Spec = { type: 'a', aProp: 'demo' }; const product = createProduct(spec);
此时返回类型仍为ProductA | ProductB,因为变量的类型是宽泛的联合类型,TypeScript无法在编译期确定其具体子类型,这是符合预期的行为。
内容的提问来源于stack exchange,提问作者Igor Soloydenko
相关产品推荐
相关产品推荐

