Function Components

通常情况下,函数式组件可以被定义为接收一个props入参,返回一个JSX元素的普通函数:

  1. type AppProps = { message: string }; /* could also use interface */
  2. const App = ({ message }: AppProps) => <div>{message}</div>;

这里我们需要注意一种场景,函数式组件只能返回JSX表达式( JSX.Element extends ReactElement )和null,因此在有些场景下我们不得不去做一些进行类型强转和断言,保证编译器能够识别:

  1. const MyArrayComponent = () => (Array(5).fill(<div />) as any) as JSX.Element;

React.FC

React中提供了接口类型 React.FC/React.FunctionComponent,通过 React.FC 来声明组件,可以显示地定义函数式组件的属性约束:

  1. const App: React.FunctionComponent<{ message: string }> = ({ message }) => (
  2. <div>{message}</div>
  3. );
  1. type FC<P = {}> = FunctionComponent<P>;
  2. interface FunctionComponent<P = {}> {
  3. (props: PropsWithChildren<P>, context?: any): ReactElement | null;
  4. propTypes?: WeakValidationMap<P>;
  5. contextTypes?: ValidationMap<any>;
  6. defaultProps?: Partial<P>;
  7. displayName?: string;
  8. }

PropsWithChildren 规定函数式组件可以接受包括children节点以及组件本身的泛型属性:

  1. type PropsWithChildren<P> = P & { children?: ReactNode };

同时,函数式组件的返回值是ReactElement或null.

Note: React.createElement() 函数的返回值是一个实现了JSX.Element ( ReactElement ) 的对象;而ReactNode 则涵盖了一个组件的多种场景下的返回类型。

Hooks

useRef

当我们使用useRef来创建ref容器时,通常有两种方式:

  1. const ref1 = useRef<HTMLElement>(null!);// 初始值为null,但强行声明使用时不为空
  2. const ref2 = useRef<HTMLElement | null>(null);

ref1.current 是只读的,通常会把ref1交给React内置的ref去维护;而ref2.current是可以修改的,我们可以用它维护自己需要的实例变量。

Custom Hooks

如果我们在自定义Hook中直接返回一个数组,TS的类型推断会把返回类型为Union Type 数组:

  1. export function useLoading() {
  2. const [isLoading, setState] = React.useState(false);
  3. const load = (aPromise: Promise<any>) => {
  4. setState(true);
  5. return aPromise.finally(() => setState(false));
  6. };
  7. return [isLoading, load] infers (boolean | typeof load)[]
  8. }

为了避免错误的类型推断,可以使用TS提供的「const assertions」:

  1. return [isLoading, load] as const; // infers [boolean, typeof load]

当然也可以显式声明为特定类型:

  1. return [isLoading, load] as [
  2. boolean,
  3. (aPromise: Promise<any>) => Promise<any>
  4. ];