Una respuesta actualizada: desde la adición de los tipos de intersección a través de &
, es posible "fusionar" dos tipos inferidos sobre la marcha.
Aquí hay un ayudante general que lee las propiedades de algún objeto from
y las 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 no todavía realizar un tipo-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}`)
}
}
);
Click here to try it out in the TypeScript Playground. Tenga en cuenta que hemos restringido foo
para que sea del tipo Foo
, por lo que el resultado de merge
tiene que ser un Foo
completo. Por lo tanto, si cambia el nombre a bar
por bad
, aparece un error de tipo.
NB Sin embargo, todavía hay un orificio de tipo aquí. TypeScript no proporciona una forma de restringir un parámetro de tipo para que sea "no una función". Entonces podría confundirse y pasar su función como el segundo argumento al merge
, y eso no funcionaría. 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;
}
Ésta no es una respuesta directa a su pregunta, pero para cualquiera que quiera para construir concisamente un objeto de función con propiedades, y está bien con el casting, el [operador Object-Spread] (https://blog.mariusschulz.com/2016/12/23/typescript-2-1-object-rest-and -spread) parece hacer el truco: 'var f: {(): any; someValue: number; } = <{(): cualquiera; someValue: number; }> { ... ((= = "Hola"), someValue: 3 }; '. – Jonathan