Una respuesta actualización: ya que la adición de tipos de intersecciones a través &, es posible "fusionar" dos tipos inferidos sobre la marcha.
Aquí está un ayudante general de que lee las propiedades de un objeto fromy los copia sobre un objeto onto. Se devuelve el mismo objeto onto, pero con un nuevo tipo que incluye dos conjuntos de propiedades, que describe tan correctamente el comportamiento de tiempo de ejecución:
function merge<T1, T2>(onto: T1, from: T2): T1 & T2 {
Object.keys(from).forEach(key => onto[key] = from[key]);
return onto as T1 & T2;
}
Este ayudante de bajo nivel tiene todavía realizar un tipo de afirmación, pero es de tipo seguro por diseño. Con esta ayuda en su lugar, tenemos un operador que podemos utilizar para resolver el problema de la OP con la seguridad de tipo completo:
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}`)
}
}
);
Haga clic aquí para probarlo en el mecanografiado de juegos . Obsérvese que se han limitado fooa ser de tipo Foo, por lo que el resultado de mergetiene que ser una completa Foo. Así que si cambia el nombre bara badcontinuación, se obtiene un error de tipo.
NB Todavía hay un agujero tipo aquí, sin embargo. Mecanografiado no proporciona una manera de limitar un parámetro de tipo de "No es una función". Por lo que podría confundirse y pasar su función como segundo argumento merge, y que no iba a funcionar. Así que hasta que esto puede ser declarada, tenemos que cogerlo en tiempo de ejecución:
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;
}