Aktualizovaný odpověď: protože přidáním typů křížení přes &to je možné „sloučit“ dva typy odvozené v reálném čase.
Zde je obecný pomocník, který čte vlastnosti nějakého objektu froma kopie je přes objekt onto. Vrátí stejný objekt onto, ale s novým typem, který obsahuje obě sady vlastností, takže správně popisuje chování za běhu:
function merge<T1, T2>(onto: T1, from: T2): T1 & T2 {
Object.keys(from).forEach(key => onto[key] = from[key]);
return onto as T1 & T2;
}
Tento low-level pomocník má ještě provést typu tvrzení, ale je to typ bezpečné záměrné. S tímto pomocníkem v místě, máme operátor, který můžeme použít k vyřešení problému OP je s plnou bezpečností typu:
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}`)
}
}
);
Klikněte sem to vyzkoušet ve strojopisu hřiště . Všimněte si, že jsme omezené foobýt typu Foo, takže výsledek mergemusí být kompletní Foo. Takže pokud jste přejmenování barse badpak dostanete chybu typu.
NB Tam je ještě jeden druh díra, nicméně. Strojopisem neposkytuje způsob, jak omezovat parametr typu, aby byl „není funkce“. Takže byste mohli dostat zmatený a předat svou funkci jako druhý argument merge, a že to nebude fungovat. Takže dokud to může být prohlášena, musíme ho chytit za běhu:
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;
}