Une réponse mise à jour: depuis l'ajout de types d'intersection via &, il est possible de « fusionner » deux types inférées à la volée.
Voici une aide générale qui lit les propriétés d'un objet fromet les copie sur un objet onto. Il retourne le même objet , ontomais avec un nouveau type qui comprend deux ensembles de propriétés, décrivant de manière correctement le comportement d'exécution:
function merge<T1, T2>(onto: T1, from: T2): T1 & T2 {
Object.keys(from).forEach(key => onto[key] = from[key]);
return onto as T1 & T2;
}
Cette aide de bas niveau ne fonctionne toujours un type d'affirmation, mais il est de type sécurisé par la conception. Avec cette aide en place, nous avons un opérateur que nous pouvons utiliser pour résoudre le problème de l'OP avec la sécurité complète du type:
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}`)
}
}
);
Cliquez ici pour l' essayer dans l'aire de jeu tapuscrit . Notez que nous avons contraint fooà être de type Foo, de sorte que le résultat de mergedoit être complète Foo. Donc , si vous renommez barpour badvous obtenez une erreur de type.
NB Il y a encore un trou de type ici, cependant. Tapuscrit ne fournit pas un moyen de contraindre un paramètre de type à « pas une fonction ». Donc , vous pourriez obtenir confus et passer votre fonction en tant que deuxième argument merge, et ne fonctionnerait pas. Donc , jusqu'à ce que cela peut être déclaré, nous devons l' attraper à l' exécution:
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;
}