From f9083401863c617d17f5703d66f89dc55dd752b1 Mon Sep 17 00:00:00 2001 From: Rasmus Eneman Date: Fri, 1 Dec 2017 14:30:39 +0100 Subject: [PATCH] [recompose]: Improve type inference of withHandlers I went ahead and added the correspondeing tests on withStateHandlers as well to make sure it also works as expected --- types/recompose/index.d.ts | 23 +++++++++++--- types/recompose/recompose-tests.tsx | 48 +++++++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 8 deletions(-) diff --git a/types/recompose/index.d.ts b/types/recompose/index.d.ts index edff2061b5..c057521570 100644 --- a/types/recompose/index.d.ts +++ b/types/recompose/index.d.ts @@ -3,6 +3,7 @@ // Definitions by: Iskander Sierra // Samuel DeSota // Curtis Layne +// Rasmus Eneman // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped // TypeScript Version: 2.6 @@ -78,13 +79,25 @@ declare module 'recompose' { // withHandlers: https://github.com/acdlite/recompose/blob/master/docs/API.md#withhandlers type EventHandler = Function; - type HandleCreators = { - [handlerName in keyof THandlers]: mapper; + // This type is required to infer TOutter + type HandleCreatorsStructure = { + [handlerName: string]: mapper; }; - type HandleCreatorsFactory = (initialProps: TOutter) => HandleCreators; + // This type is required to infer THandlers + type HandleCreatorsHandlers = { + [P in keyof THandlers]: (props: TOutter) => THandlers[P]; + }; + type HandleCreators = + & HandleCreatorsStructure + & HandleCreatorsHandlers + type HandleCreatorsFactory = (initialProps: TOutter) => + HandleCreators; + export function withHandlers( - handlerCreators: HandleCreators | HandleCreatorsFactory - ): InferableComponentEnhancerWithProps; + handlerCreators: + | HandleCreators + | HandleCreatorsFactory + ): InferableComponentEnhancerWithProps; // defaultProps: https://github.com/acdlite/recompose/blob/master/docs/API.md#defaultprops export function defaultProps( diff --git a/types/recompose/recompose-tests.tsx b/types/recompose/recompose-tests.tsx index 1504ab563a..c239cbacb1 100644 --- a/types/recompose/recompose-tests.tsx +++ b/types/recompose/recompose-tests.tsx @@ -120,10 +120,35 @@ function testWithHandlers() { /> ) - const handlerNameTypecheckProof = withHandlers({ + const handlerNameTypecheckProof = withHandlers({ // $ExpectError onChange: () => () => {}, - notAKeyOnHandlerProps: () => () => {}, // $ExpectError + notAKeyOnHandlerProps: () => () => {}, }); + + // The inner props should be fully inferrable + const enhancer3 = withHandlers({ + onChange: (props: OutterProps) => (e: any) => {}, + onSubmit: (props: OutterProps) => (e: React.MouseEvent) => {}, + }); + const Enhanced3 = enhancer3(({onChange, onSubmit, out}) => +
{out}
); + const rendered3 = ( + + ) + + const enhancer4 = withHandlers((props: OutterProps) => ({ + onChange: (props) => (e: any) => {}, + onSubmit: (props) => (e: React.MouseEvent) => {}, + })); + const Enhanced4 = enhancer4(({onChange, onSubmit, out}) => +
{out}
); + const rendered4 = ( + + ) } function testDefaultProps() { @@ -220,7 +245,24 @@ function testWithStateHandlers() { (props: OutterProps) => ({ counter: props.initialCounter }), { notAKeyOfUpdaters: (state, props) => n => ({ ...state, counter: state.counter + n ** props.power }), }, // $ExpectError ); - } + + // The inner props should be fully inferrable + const enhancer2 = withStateHandlers( + (props: OutterProps) => ({ counter: props.initialCounter }), + { + add: (state, props) => n => ({ ...state, counter: state.counter + n ** props.power }), + }, + ); + const Enhanced2 = enhancer((props) => +
+
{`Counts from: ${props.initialCounter}`}
+
{`Counter: ${props.counter}`}
+
props.add(2)}>
+
); + const rendered2 = ( + + ); +} function testWithReducer() { interface State { count: number }