typescript - 基于输入类型的函数返回类型映射
问题描述
我有一个叫做 createProduct 的函数,它接受一个 Spec 作为输入,并生成一个 Product 作为输出。
Spec 使用判别联合(type: 'a' | 'b')。类型 ProductA 和 ProductB 不兼容,因为它们在字段定义上没有重叠。
有没有办法对 createProduct 进行类型定义,以确保当使用 SpecA 时,它会生成 ProductA,而当使用 SpecB 时,它会生成 ProductB?基本上,我在寻找某种类型映射。伪代码:createProduct<Spec=SpecA|SpecB>(spec: Spec): <SpecA => ProductA | SpecB => ProductB>
当然,如果我传递一个类型为 Spec 的 spec 变量,这是行不通的。但我认为,如果我传递一个字面量作为参数,例如 { type: 'a' },应该是可以实现的。
代码
type Spec = SpecA | SpecB;
interface SpecA {
type: 'a';
}
interface SpecB {
type: 'b';
}
type Product = ProductA | ProductB;
interface ProductA {
properyA: 'unique property of A';
}
interface ProductB {
properyB: 'unique property of B';
}
export function createProduct(spec: Spec): Product {
if (spec.type === 'a') return { properyA: 'unique property of A' };
else if (spec.type === 'b') return { properyB: 'unique property of B' };
else return spec; // spec: never
}
export function consumeProductCreator(): void {
const product = createProduct({ type: 'a' });
// The type of `product` is just `Product` but I want it to be inferred as `ProductA`
// by adjusting the signature of `createProduct` function.
}
答案#1
如果你添加两个重载,它应该可以工作:
export function createProduct(spec: SpecA): ProductA;
export function createProduct(spec: SpecB): ProductB;
export function createProduct(spec: Spec): Product {
if (spec.type === 'a') return { properyA: 'unique property of A' };
else if (spec.type === 'b') return { properyB: 'unique property of B' };
else return spec; // spec: never
}
现在是:
export function consumeProductCreator(): void {
const product = createProduct({ type: 'a' });
// ^? const product: ProductA
}
有关更多详细信息,请参阅关于定义函数重载的文档(实际上只是签名重载,因为你无法像在其他语言如 Java 中那样重载实现——但在这种情况下你不需要这样做):
- https://www.typescriptlang.org/docs/handbook/2/functions.html#function-overloads
