在React函数式组件里使用TypeScript的类型检查

December 12, 2019 ... ☕️ 4 min read

自从React推出了Hooks,很多项目都慢慢变成了函数式组件,一是代码量降低,减少了很多生命周期调用和代码冗余;二是相对于class,还是function的写法更习惯。

强烈建议阅读:react-typescript-cheatsheet

props属性

函数式组件,一般都会以参数形式传入props。由于来源于上级组件或者其他地方,所以这部分会导致可控程度降低,如果加上有效的类型检查,就会好很多。除了TypeScript,React也提供了PropTypes的类型检查机制。先说TypeScript。

一般情况下,如果需要用到props里存储的内容,就需要先声明类型

type AppProps = {
  name: string
};

const App = (props: AppProps) {  return (<div>{props.name}</div>);
}

咋一看,这不是和PropTypes一样吗?

区别在于:TypeScript是编译时的类型检查,PropTypes是运行时的类型检查。这里有一篇回答,几种情况下不能相互替代。

但是,有一个插件,可以将TypeScript的类型检查,变为PropTypes。迷不迷。。

useState

通常useState的类型可以由设置的初始值来推测,但是如果初始为null就不行了。所以还是要指定一个类型。

const [state, setState] = React.useState({
  foo: 1,
  bar: 2
}); // state's type inferred to be {foo: number, bar: number}

const [value, setValue] = useState<number | null>(null);

如果这个类型的类型推测比较确定(比如上面例子中的state),那么使用的时候可以用typeof。

const setMethod = (obj: typeof state) {
  setState(obj);
}

useEffect

useEffect接受一个处理函数,(可选)一个清理函数,由于不用处理返回值,所以通常不用注意类型。但是有一个情况,就是箭头函数的时候,不带大括号,容易忽略这是一个返回值,使用setTimeout这些默认会返回内容的时候就会有错误。

// setTimeout会返回一个timeoutID(数字),但是useEffect的返回内容必须是一个函数或者undefined
useEffect(
    () =>
      setTimeout(() => {
        /* do stuff */
      }, timerMs)
  );

Event类型

如果直接在属性上写处理函数,通常TypeScript会推断出对应的类型。

const el = (
  <button
    onClick={event => {      /* ... */
    }}
  />
);

不过如果需要单独写处理函数,就需要自己指定类型了。

但是坏消息是React有自己的一套事件系统。其中一些名字虽然熟悉,但是内容不一样。React当然考虑到了这个问题,所以基本的属性还是有的,扩展内容根据需要取就好了。

如果不太想管具体事件类型,比如只想preventDefault,可以直接用React.SyntheticEvent。因为SyntheticEvent(合成事件)是通用的,所有浏览器事件都拿它包装了一层。

如果需要用event.target(比如取值)的时候,单独给它指定对应类型即可

const changeValue = (e: React.SyntheticEvent) => {  let element = event.target as HTMLInputElement;
  let value = element.value;
  setValue(value);
};

当然,也可以直接指定

const changeValue = (e: React.FormEvent<HTMLInputElement>) => {  setValue(e.target.value);
};

#TypeScript#React