更新的答案:由于通过添加交集类型&
,因此可以动态“合并”两种推断类型。
这是一个通用助手,它读取某个对象的属性from
并将它们复制到一个对象onto
上。它返回相同的对象onto
,但具有包含两组属性的新类型,因此正确描述了运行时行为:
function merge<T1, T2>(onto: T1, from: T2): T1 & T2 {
Object.keys(from).forEach(key => onto[key] = from[key]);
return onto as T1 & T2;
}
这个低级助手仍然执行类型断言,但它在设计上是类型安全的。有了这个助手,我们就有了一个操作符,我们可以用它来解决完全类型安全的 OP 问题:
interface Foo {
(message: string): void;
bar(count: number): void;
}
const foo: Foo = merge(
(message: string) => console.log(`message is ${message}`), {
bar(count: number) {
console.log(`bar was passed ${count}`)
}
}
);
单击此处在 TypeScript Playground 中试用。请注意,我们已经限制foo
为 type Foo
,因此 的结果merge
必须是完整的Foo
. 因此,如果您重命名bar
为,bad
则会出现类型错误。
注意这里仍然有一种类型的孔,但是。TypeScript 没有提供将类型参数约束为“不是函数”的方法。因此,您可能会感到困惑,并将您的函数作为第二个参数传递给merge
,但这是行不通的。因此,在可以声明之前,我们必须在运行时捕获它:
function merge<T1, T2>(onto: T1, from: T2): T1 & T2 {
if (typeof from !== "object" || from instanceof Array) {
throw new Error("merge: 'from' must be an ordinary object");
}
Object.keys(from).forEach(key => onto[key] = from[key]);
return onto as T1 & T2;
}