Een bijgewerkte antwoord: sinds de toevoeging van kruising types via &, is het mogelijk om "samen te voegen" twee afgeleide types on the fly.
Hier is een algemeen helper dat de eigenschappen van een object leest fromen kopieert ze over een object onto. Retourneert hetzelfde object ontomaar met een nieuw type dat beide eigenschappen bestaat, zo correct beschrijft de runtime-gedrag:
function merge<T1, T2>(onto: T1, from: T2): T1 & T2 {
Object.keys(from).forEach(key => onto[key] = from[key]);
return onto as T1 & T2;
}
Deze low-level helper nog steeds het uitvoeren van een type bewering, maar het is het type-safe door het ontwerp. Met deze helper in de plaats hebben we een operator die we kunnen gebruiken om het probleem van de OP's op te lossen met volledige typeveiligheid:
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}`)
}
}
);
Klik hier om het uit te proberen in de typoscript Playground . Merk op dat we hebben beperkt foovan het type te zijn Foo, dus het resultaat van mergemoet een compleet zijn Foo. Dus als je een andere naam geven barom baddan krijg je een soort fout.
NB Er is nog steeds een soort gat hier, echter. Typescript voorziet niet in een manier om een parameter type beperken tot "geen functie" te zijn. Dus je zou kunnen raken in de war en geef uw functie als het tweede argument aan merge, en dat zou niet werken. Dus totdat dit kan worden verklaard, moeten we hem te vangen op runtime:
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;
}