Eine aktualisierte Antwort: seit dem Hinzufügen von Kreuzungstypen über &
ist es möglich, zwei abgeleitete Typen im laufenden Betrieb "zusammenzuführen".
Hier ist ein allgemeiner Helfer, der die Eigenschaften eines Objekts liest from
und über ein Objekt kopiert onto
. Es gibt dasselbe Objekt zurück, onto
jedoch mit einem neuen Typ, der beide Eigenschaftensätze enthält, sodass das Laufzeitverhalten korrekt beschrieben wird:
function merge<T1, T2>(onto: T1, from: T2): T1 & T2 {
Object.keys(from).forEach(key => onto[key] = from[key]);
return onto as T1 & T2;
}
Dieser Low-Level-Helfer führt zwar noch eine Typzusicherung durch, ist jedoch von Natur aus typsicher. Mit diesem Helfer haben wir einen Bediener, mit dem wir das OP-Problem mit voller Sicherheit lösen können:
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}`)
}
}
);
Klicken Sie hier, um es auf dem TypeScript-Spielplatz auszuprobieren . Beachten Sie, dass wir uns darauf beschränkt haben foo
, vom Typ zu sein Foo
, daher muss das Ergebnis von merge
vollständig sein Foo
. Also, wenn Sie umbenennen bar
inbad
Sie einen Tippfehler.
Hinweis: Hier gibt es jedoch noch ein Loch. TypeScript bietet keine Möglichkeit, einen Typparameter auf "keine Funktion" zu beschränken. Sie könnten also verwirrt sein und Ihre Funktion als zweites Argument an übergeben merge
, und das würde nicht funktionieren. Bis dies deklariert werden kann, müssen wir es zur Laufzeit abfangen:
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;
}
var f: { (): any; someValue: number; } = <{ (): any; someValue: number; }>{ ...(() => "Hello"), someValue: 3 };
.