diff --git a/src/observableTypes.ts b/src/observableTypes.ts index fe6c8171..70f4999a 100644 --- a/src/observableTypes.ts +++ b/src/observableTypes.ts @@ -150,7 +150,7 @@ type ObservableFunctionChildren = { ? T[K] : t extends Observable ? t - : Observable & (() => t) + : Observable & T[K] : T[K] & Observable; }; diff --git a/tests/types.test.ts b/tests/types.test.ts index 3ac5c4ff..572de67b 100644 --- a/tests/types.test.ts +++ b/tests/types.test.ts @@ -131,6 +131,46 @@ describe('observable', () => { type ObservableFn2 = ReturnType; expectTypeOf().returns.toEqualTypeOf(); }); + + it('issue #631: function child preserves argument signature', () => { + type AppState = { + // A function returning a non-void value previously had its argument signature + // stripped down to `() => boolean`, so calling it errored with + // `Expected 0 arguments, but got 1`. + centerMap: (coords: unknown) => boolean; + }; + + function withFunctionChild() { + return observable({ + centerMap: (coords) => !!coords, + }); + } + + type ObservableFn = ReturnType; + + // The function's argument signature must be preserved. + expectTypeOf().toBeCallableWith('some-coords'); + expectTypeOf().parameters.toEqualTypeOf<[coords: unknown]>(); + }); + + it('issue #521: async function child without args keeps its Promise return type', () => { + type Example = { + // Without arguments the Promise return was wrongly unwrapped to `number`. + asyncNoArgs(): Promise; + }; + + function withAsyncChildren() { + return observable({ + async asyncNoArgs() { + return 1; + }, + }); + } + + type ObservableFn = ReturnType; + + expectTypeOf().returns.toEqualTypeOf>(); + }); }); describe('Observable', () => {