diff --git a/types/react/index.d.ts b/types/react/index.d.ts index 3f992f6e8f..06bc3ae590 100644 --- a/types/react/index.d.ts +++ b/types/react/index.d.ts @@ -21,6 +21,7 @@ // Saransh Kataria // Kanitkorn Sujautra // Sebastian Silbermann +// Chris Sauve // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped // TypeScript Version: 2.8 @@ -804,7 +805,9 @@ declare namespace React { // based on the code in https://github.com/facebook/react/pull/13968 // Unlike the class component setState, the updates are not allowed to be partial - type SetStateAction = S | ((prevState: S) => S); + type SetStateAction = S extends ((...args: any[]) => any) ? + (prevState: S) => S : + (S | ((prevState: S) => S)); // this technically does accept a second argument, but it's already under a deprecation warning // and it's not even released so probably better to not define it. type Dispatch = (value: A) => void; diff --git a/types/react/test/hooks.tsx b/types/react/test/hooks.tsx index 70ea9a0ce7..e7e6585207 100644 --- a/types/react/test/hooks.tsx +++ b/types/react/test/hooks.tsx @@ -201,6 +201,14 @@ function useEveryHook(ref: React.Ref<{ id: number }>|undefined): () => boolean { // make sure the generic argument does reject actual potentially undefined inputs // $ExpectError React.useState(undefined)[0]; + // When state is a function type, it must be returned from a function, + // not provided directly. + // $ExpectError + React.useState<(() => boolean)>(() => true)[1](() => false); + // Returning a function for state is fine + React.useState<(() => boolean)>(() => true)[1](() => () => false); + // As is returning non-function members of a union + React.useState<(() => boolean) | number>(() => true)[1](() => 42); // useReducer convenience overload