Preact useState类型疑问:((prevState: null) => null) | null含义等问题
问题场景
先看这段Preact代码:
import { useState } from "preact/hooks"; export default function Test() { const [state, setState] = useState(null); setState('string'); }
运行时会抛出TypeScript错误:
Argument of type 'string' is not assignable to parameter of type '(prevState: null) => null'.deno-ts(2345)
如果把初始值换成数字1:
- const [state, setState] = useState(null); + const [state, setState] = useState(1);
错误提示变成:
Argument of type 'string' is not assignable to parameter of type 'number | ((prevState: number) => number)'.deno-ts(2345)
疑惑解答
1. ((prevState: null) => null) | null 是什么含义?
这是TypeScript的联合类型,表示这个位置的取值只能是以下两种类型之一:
- 一个函数:接收类型为
null的prevState参数,返回值必须也是null - 直接传入
null值
简单说就是调用setState时,要么传null,要么传一个能把旧的null状态转换成新null的函数。
2. 为什么初始值为null时,要求的类型不是 null | ((prevState: null) => null)?
这是TypeScript类型推导的特性:当你给useState传入null作为初始值时,TypeScript会把状态类型推导为单一的null类型(而非包含null的联合类型)。此时setState的参数类型实际上是null | ((prevState: null) => null),但你传入的'string'既不是null也不符合函数类型,TypeScript在报错时优先展示了和传入值差异较大的函数类型。
而当初始值是1(数字字面量)时,TypeScript推导状态类型为number,setState的参数类型是number | ((prevState: number) => number)——这里错误提示列出了完整的联合类型,是因为string和这两个类型都不匹配,所以TypeScript把所有可选类型都展示了出来。
3. 如何使用多类型状态?例如初始值为1或null,后续将值设置为'string'?
需要手动给useState指定联合类型,明确声明状态允许的所有类型:
import { useState } from "preact/hooks"; export default function Test() { // 明确指定状态可以是 number、null 或 string const [state, setState] = useState<number | null | string>(1); setState('string'); // 正常运行,无报错 setState(null); // 支持设置为null setState(2); // 支持设置为数字 }
如果初始值是null,想要后续支持其他类型,同样手动指定联合类型即可:
const [state, setState] = useState<string | null>(null); setState('hello'); // 正常工作
内容的提问来源于stack exchange,提问作者Ooker

