TypeScript认为useState返回[T|未定义,...],为什么?

ep6jt1vc  于 2023-02-13  发布在  TypeScript
关注(0)|答案(3)|浏览(201)

如果我声明一个类型如下

type UseBoolean = ReturnType<typeof React.useState<boolean>>;

UseBoolean被推断为

[boolean | undefined, React.Dispatch<React.SetStateAction<boolean | undefined>>]

但是当我查看React.useState的源代码时,

function React.useState<S>(initialState: S | (() => S)): [S, React.Dispatch<React.SetStateAction<S>>]

这让我觉得UseBoolean应该

[boolean, React.Dispatch<React.SetStateAction<boolean>>]

那为什么不是呢

sauutmhj

sauutmhj1#

但是当我查看React.useState的源代码时...
在它下面还有第二个重载,它被你的类型拾取(但是我们可以修复它,继续阅读):

function useState<S = undefined>(): [S | undefined, Dispatch<SetStateAction<S | undefined>>];

它允许用户不为状态成员提供初始值的情况。例如(playground link):

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>>]

我想不出只获取第一个重载的方法,但我们可以删除具有Map类型的undefined

type NoUndefinedState<T> =
    T extends [infer S | undefined, React.Dispatch<React.SetStateAction<infer S | undefined>>]
    ? [S, React.Dispatch<React.SetStateAction<S>>]
    : never;

然后:

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>>]

Playground链接
如果需要,我们可以简化创建UseXYZ类型的过程:

type UseStateTuple<T> = NoUndefinedState<ReturnType<typeof React.useState<T>>>;

那么使用它就是:

type UseBoolean = UseStateTuple<boolean>;
//   ^? type UseBoolean = [boolean, React.Dispatch<React.SetStateAction<boolean>>]

type UseString = UseStateTuple<string>;
//   ^? type UseString = [string, React.Dispatch<React.SetStateAction<string>>]

Playground链接

xqk2d5yq

xqk2d5yq2#

在TypeScript中使用useState挂接时,可以指定该挂接所管理的状态的类型。在您的情况下,该类型定义为UseBoolean。但是,由于没有显示任何代码来演示该挂接的用法,因此假定您没有提供初始值。因此,下面的代码:
const [bool, setBool] = useState<boolean>();
将导致boolean | undefined类型。
如果我说的不正确,请提供更多的例子来说明useState钩子的用法。

5tmbdcev

5tmbdcev3#

UseBoolean不被推断为[boolean,React.Dispatch]的原因<React.SetStateAction>是TypeScript推断泛型函数类型的方式。
当您使用布尔参数调用React.useState时,TypeScript会正确地将返回元组的类型推断为[boolean,React.Dispatch<React.SetStateAction>]。
但是,当您使用ReturnType〈typeof React.useState〉提取useState函数的返回类型时,TypeScript会丢失传递给useState的类型参数boolean的相关信息。因此,为UseBoolean推断的类型是useState的原始返回类型,其中包括类型参数S。
由于类型参数S可以是任何类型,因此TypeScript保守地将其推断为布尔值|undefined,这意味着返回的元组[boolean|未定义,React分派〈React设置状态操作〈布尔值|undefined〉〉]包括布尔值和undefined作为可能的值。

相关问题