TypeScript中能否在编译时判断类型并实现参数包装函数?
问题描述
我有类型A或B的实例,想要创建一个单一函数,接收A或B类型的参数,并返回对应的包装后的参数。我写了示例代码,但不确定在TypeScript中能否实现该需求:
type A = { name: string }; type B = A[]; type DucktypedA = { a: A, }; type DucktypedB = { b: B, } function test(arg: A | B): DucktypedA | DucktypedB { if (arg instanceof A) { return { a: arg }; } else { return { b: arg }; } }
期望的调用结果:
const a = { name: "me" }; const wrappedA = test(a); // --> { a: { name: "me" } } const b = [{ name: "me" }]; const wrappedB = test(b); // --> { b: [{ name: "me" }] }
解决方案
可以实现,但你当前代码里的arg instanceof A无法生效——因为A是TypeScript的类型别名,编译后会被完全擦除,JavaScript运行时根本不知道A的存在,自然无法用instanceof做判断。
要实现需求,需要用运行时可识别的逻辑区分A和B:由于B是A的数组类型,我们可以用Array.isArray()来判断参数是否为数组,同时结合TypeScript的类型守卫让类型推断生效。
方式一:函数重载+类型守卫
这种方式的类型推断最直观,能明确对应输入输出的类型关系:
type A = { name: string }; type B = A[]; type DucktypedA = { a: A }; type DucktypedB = { b: B }; // 函数重载:声明不同输入对应的输出类型 function test(arg: A): DucktypedA; function test(arg: B): DucktypedB; // 实际实现逻辑 function test(arg: A | B): DucktypedA | DucktypedB { if (Array.isArray(arg)) { return { b: arg }; } else { return { a: arg }; } } // 调用验证 const a = { name: "me" }; const wrappedA = test(a); // 类型自动推断为 DucktypedA const b = [{ name: "me" }]; const wrappedB = test(b); // 类型自动推断为 DucktypedB
方式二:泛型+条件类型
如果希望函数的返回类型更动态,可以用泛型结合条件类型实现:
type A = { name: string }; type B = A[]; // 条件类型:根据输入类型自动映射包装类型 type Ducktyped<T> = T extends A ? { a: T } : { b: T }; function test<T extends A | B>(arg: T): Ducktyped<T> { if (Array.isArray(arg)) { return { b: arg } as Ducktyped<T>; } else { return { a: arg } as Ducktyped<T>; } } // 调用验证 const wrappedA = test({ name: "me" }); // 类型为 { a: { name: string } } const wrappedB = test([{ name: "me" }]); // 类型为 { b: { name: string }[] }
两种方式都能完全满足你的需求,可根据实际场景选择使用。
内容的提问来源于stack exchange,提问作者hugotsoma
相关产品推荐
相关产品推荐

