reactjs - TypeScript piensa que useState devuelve [T | undefined, ...], ¿por qué?
Si declaro un tipo de la siguiente manera
type UseBoolean = ReturnType<typeof React.useState<boolean>>;
UseBoolean se infiere que es
[boolean | undefined, React.Dispatch<React.SetStateAction<boolean | undefined>>]
Pero cuando miro el código fuente de React.useState,
function React.useState<S>(initialState: S | (() => S)): [S, React.Dispatch<React.SetStateAction<S>>]
esto me haría pensar que UseBoolean debería ser
[boolean, React.Dispatch<React.SetStateAction<boolean>>]
¿Entonces por qué no lo es?
Respuesta #1
Pero cuando miro el código fuente de
React.useState...
Hay una segunda sobrecarga debajo de ella, que está siendo tomada por tu tipo (pero podemos arreglar eso, sigue leyendo):
function useState<S = undefined>(): [S | undefined, Dispatch<SetStateAction<S | undefined>>];
Está ahí para permitir el caso en el que el usuario no proporcione un valor inicial para el miembro de estado. Ejemplo (enlace al playground):
import React from "react";
// With no initial value:
const ex1 = React.useState<boolean>();
// ^? const ex1: [boolean | undefined, React.Dispatch<SetStateAction<boolean | undefined>>]
// With an initial value:
const ex2 = React.useState<boolean>(true);
// ^? const ex2: [boolean, React.Dispatch<SetStateAction<boolean>>]
No se me ocurre una manera de tomar solo la primera sobrecarga, pero podemos eliminar el undefined con un tipo mapeado:
type NoUndefinedState<T> =
T extends [infer S | undefined, React.Dispatch<React.SetStateAction<infer S | undefined>>]
? [S, React.Dispatch<React.SetStateAction<S>>]
: never;
Entonces :
type UseBoolean = NoUndefinedState<ReturnType<typeof React.useState<boolean>>>;
// ^? type UseBoolean = [boolean, React.Dispatch<React.SetStateAction<boolean>>]
type UseString = NoUndefinedState<ReturnType<typeof React.useState<string>>>;
// ^? type UseString = [string, React.Dispatch<React.SetStateAction<string>>]
Enlace del parque
Si queremos, podemos hacer que sea más sencillo crear estos tipos UseXYZ:
type UseStateTuple<T> = NoUndefinedState<ReturnType<typeof React.useState<T>>>;
Entonces usarlo es:
type UseBoolean = UseStateTuple<boolean>;
// ^? type UseBoolean = [boolean, React.Dispatch<React.SetStateAction<boolean>>]
type UseString = UseStateTuple<string>;
// ^? type UseString = [string, React.Dispatch<React.SetStateAction<string>>]
Enlace del parque
Respuesta #2
Cuando usas el hook useState en TypeScript, puedes especificar el tipo del estado que está siendo gestionado por el hook. En tu caso, el tipo está definido como UseBoolean. Sin embargo, dado que no se muestra ningún código que demuestre el uso del hook, se asume que no proporcionaste un valor inicial. Como resultado, el siguiente código:
const [bool, setBool] = useState<boolean>();resultará en un tipo de boolean | undefined.
Si estoy equivocado, por favor proporcione ejemplos adicionales para ilustrar el uso del hook useState.
