Una risposta aggiornamento: dal momento che l'aggiunta di tipi intersezione via &, è possibile "fondere" due tipi desunti al volo.
Ecco un aiutante generale, che legge le proprietà di un oggetto frome li copia su un oggetto onto. Restituisce lo stesso oggetto ontoma con un nuovo tipo che comprende due serie di proprietà, così correttamente descrivere il comportamento di esecuzione:
function merge<T1, T2>(onto: T1, from: T2): T1 & T2 {
Object.keys(from).forEach(key => onto[key] = from[key]);
return onto as T1 & T2;
}
Questo aiutante di basso livello non ancora esegue un tipo di affermazione, ma è type-safe di progettazione. Con questo helper in atto, abbiamo un operatore che possiamo utilizzare per risolvere il problema del PO, con la sicurezza di tipo integrale:
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}`)
}
}
);
Clicca qui per provarlo nel dattiloscritto Playground . Si noti che abbiamo vincolata fooad essere di tipo Foo, quindi il risultato di mergedeve essere un completo Foo. Quindi, se si rinomina bara badallora si ottiene un errore di tipo.
NB C'è ancora un buco tipo qui, tuttavia. Dattiloscritto non fornisce un modo per vincolare un parametro di tipo essere "non una funzione". Così si potrebbe confondersi e passare la vostra funzione come secondo argomento a merge, e che non avrebbe funzionato. Così fino a quando questo può essere dichiarato, dobbiamo prenderlo in fase di esecuzione:
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;
}