From 598ffd0b99dcfa511ab6056d9652c99665a7bbe4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Sauv=C3=A9?= Date: Wed, 19 Jun 2019 19:39:07 -0400 Subject: [PATCH] [react] Only allow thunks in useState when setting state that is a function (#36080) * Only allow thunks for function state * Add self to contributors list * Fix bounds to be more precise, and split into multiple lines. * Update index.d.ts --- types/react/index.d.ts | 5 ++++- types/react/test/hooks.tsx | 8 ++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) 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