# 前言

记录 eact 开发中常见类型定义。以下类型定义在不同的版本中可能会有报错。

# 一. 类组件

  1. 主要定义为:React.PureComponent<P,S,SS>

Pprops 的类型,Sstate 的类型(可不定义,state的类型会自己推断),SSgetSnapshotBeforeUpdate返回值。

render 方法返回ReactNode

interface AppProps {
  value: string;
}
interface AppState {
  count: number;
}
class App extends React.Component<AppProps, AppState> {
  static defaultProps = {
    value: "",
  };
  state = {
    count: 0,
  };
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 二. 函数组件

  1. React.FC

React.FC的意思是FunctionComponent,如果使用了React.FC,它在定义里就已经规定好了children的类型和函数的返回值,所以可以直接用 children

render方法返回 ReactElement。

interface AppProps {
  value?: string;
}
const App: React.FC<AppProps> = ({ value = "", children }) => {
  // ...
};
1
2
3
4
5
6
  1. props

需要自己定义children的类型

interface AppProps {
  value?: string;
  children?: React.ReactNode; // 自己定义children的类型
}

function App({ value = "", children }: AppProps) {
  return <>{children}</>;
}
1
2
3
4
5
6
7
8

# 三. Hooks 声明

# 1. useState

const [state, setState] = useState(''); // state的类型为string,自动推断
const [state, setState] = useState<string>(); // state的类型为 string | undefined
// 给初值
const [state, setState] = useState<string | null>(null); // state的类型为 string | null
1
2
3
4

# 2. useRef

const ref = useRef(""); // ref.current的类型为 string
// 泛型
type Value = { value: string };
const ref = useRef < Value > { value: "" };
// ref为html元素;需要注意的是如果ref为元素,那么初始值得写个null才不会报错
const ref = useRef < HTMLDivElement > null;
return <div ref={ref} />;
const ref1 = React.useRef < HTMLInputElement > null; //ref1.current 是只读的
const ref2 = (React.useRef < HTMLInputElement) | (null > null); //ref2.current 是可变的✅
//可是这样声明貌似不能使用ref来保存setTimeout❌
const ref1 = React.useRef < any > null; //暂时这样吧
//一个场景focus
const onButtonClick = () => {
  ref2.current?.focus(); //可以使用可选链
};

//其他
// 存储div dom
const divRef = (React.useRef < HTMLDivElement) | (null > null);

// 存储button dom
const buttonRef = (React.useRef < HTMLButtonElement) | (null > null);

// 存储a dom
const linkRef = (React.useRef < HTMLLinkElement) | (null > null);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 3. useReducer

// state类型
interface ReducerState {
  value: string;
}
// action类型;Action也可以是多个不同的Action的联合类型
interface AnyAction {
  type: string;
  [key: string]: any;
}
// reducer函数
const reducer: React.Reducer<ReducerState, AnyAction> = (state, action) => {
  switch (action.type) {
    default:
      return state;
  }
};
// 初始值
const initialState: ReducerState = { value: "" };

const [state, dispatch] = useReducer(reducer, initialState);
// state 的类型为 ReducerState
// dispatch 的类型为 React.Dispatch<AnyAction>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 4. useImperativeHandle

// props
interface AppProps {
  value: string;
}
// useImperativeHandle获取到ref的类型
interface Handle {
  get: () => string;
}

const App = React.forwardRef<Handle, AppProps>(({ value }, ref) => {
  // 定义
  useImperativeHandle(ref, () => ({
    get: () => `handle get value : ${value}`,
  }));
  return null;
});
// 使用
const handleRef = useRef<Handle>(null);
// handleRef.current?.get();
return <App value="hello" ref={handleRef} />;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 5. React.forwardRef

React.forwardRef<T, P = {}>,只需要传props的类型和ref的类型,第一个Tref的类型,Pprops的类型。

const App = React.forwardRef<HTMLDivElement, AppProps>(({ value }, ref) => {
  return <div ref={ref} />;
});
// 使用
const ref = useRef<HTMLDivElement>(null);
return <App value="hello" ref={ref} />;
1
2
3
4
5
6

# 6. React.ForwardRefRenderFunction

// 定义
const forwardRender: React.ForwardRefRenderFunction<
  HTMLDivElement,
  AppProps
> = ({ value }, ref) => {
  return <div ref={ref} />;
};
const App = React.forwardRef(forwardRender);
// 使用
const ref = useRef < HTMLDivElement > null;
return <App value="hello" ref={ref} />;
1
2
3
4
5
6
7
8
9
10
11

# 7. React.createContext

泛型有自动推断的功能,所以 useContext 就不需要再写上类型了

interface ContextType {
  getPrefixCls: (value: string) => string;
}

const context =
  React.createContext <
  ContextType >
  {
    getPrefixCls: (value) => `prefix-${value}`,
  };

const App = () => {
  const { getPrefixCls } = useContext(context);
  getPrefixCls("App"); // prefix-App
  return null;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 8. React.cloneElement

如果使用的React.FC 定义的组件,它的 children 类型默认是React.ReactNode,需要显式转为 React.ReactElement

const App: React.FC = ({ children }) => {
  return React.cloneElement(children as React.ReactElement, { value: "hello" });
};
// 也可以覆写定义
const App: React.FC<{ children: React.ReactElement }> = ({ children }) => {
  return React.cloneElement(children, { value: "hello" });
};
1
2
3
4
5
6
7

# 9. React.ComponentType

通过React.ComponentType<P>定义的组件可以将变量名传入组件,在组件内调用,高阶组件通常会使用

interface AppProps {
  value: string;
}
const App: React.FC<AppProps> = (props) => {
  return null;
};
// React.ComponentType定义组件
function HOC<T>(Component: React.ComponentType<T>) {
  return function(props: T) {
    return <Component {...props} />;
  };
}
const WrappedComponent = HOC(App);
// 调用
<WrappedComponent value="hello" />;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 10. 泛型参数的组件

泛型参数的组件是 typescript2.9 版本新增的。通过传入的类型泛型 判断 props 类型。需要作用到很多类型的时候使用泛型

<Select<number>>
  <Select.Option value={1}>1</Select.Option>
  <Select.Option value={2}>2</Select.Option>
</Select>
1
2
3
4

# 11. 自定义hook

自定钩子还需要定义返回值才行

const useCustomHook = (): [string, (value: string) => void] => {
  const [state, setState] = useState("");
  const set = (value: string) => {
    if (!value) return;
    setState(value);
  };
  return [state, set];
};
// 使用
const [state, setState] = useCustomHook();
setState("hello");
1
2
3
4
5
6
7
8
9
10
11

# 12. useCallback

// 自动推断 (value: number) => number

const multiply = React.useCallback((value: number) => value * multiplier, [
  multiplier,
])

//泛型
//同时也支持传入泛型, useMemo 的泛型指定了返回值类型,useCallback 的泛型指定了参数类型

const handleChange = React.useCallback<
  React.ChangeEventHandler<HTMLInputElement>
>(evt => {
  console.log(evt.target.value)
}, [])

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 四. 自定义类组件的定义

// 定义泛型参数的组件
class GenericComponent<P> extends React.Component<P> {
  internalProp: P;
  constructor(props: P) {
    super(props);
    this.internalProp = props;
  }
  render() {
    return null;
  }
}

type Props = { a: number; b: string };

<GenericComponent<Props> a={10} b="hi" />; // OK
<GenericComponent<Props> a={10} b={20} />; // Error
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 五. 自定义函数组件的定义

function GenericComponent<P>(props: P) {
  const internalProp = useRef(props);
  return null;
}
1
2
3
4

箭头函数的组件在特定条件也能用泛型

// 这样会解析错误
const GenericComponent = <P>(props: P) =>{
  const internalProp = useRef(props);
  return null;
}

// 泛型必须使用extends关键字才能解析
const GenericComponent = <P extends any>(props: P) =>{
  const internalProp = useRef(props);
  return null;
}
1
2
3
4
5
6
7
8
9
10
11

# 六. 事件处理

  1. 示例 1
const App = () => {
  // React.MouseEventHandler
  const onClick: React.MouseEventHandler<HTMLInputElement> = (e) => {
    console.log(e.currentTarget.value);
  };
  // React.ChangeEventHandler
  const onChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {
    console.log(e.currentTarget.value);
  };
  // React.FocusEventHandler
  const onFocus: React.FocusEventHandler<HTMLInputElement> = (e) => {
    console.log(e.currentTarget.value);
  };
  return <input onClick={onClick} onChange={onChange} onFocus={onFocus} />;
};
// React.SyntheticEvent
const onSubmit = (e: React.SyntheticEvent) => {
    e.preventDefault()
    const target = e.target as typeof e.target & {
      password: { value: string }
    } // 类型扩展---表示看不懂---
    const password = target.password.value
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  1. 示例 2
import * as React from "react";
//第一种,
type changeFn = (e: React.FormEvent<HTMLInputElement>) => void; //这样定义下面onchange的参数和返回值
const App: React.FC = () => {
  const [state, setState] = React.useState("");
  const onChange: changeFn = (e) => {
    setState(e.currentTarget.value);
  };
  //第二种,强制使用 @types / react 提供的委托类型
  const onChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {
    setState(e.currentTarget.value);
  };
  return (
    <div>
      <input type="text" value={state} onChange={onChange} />
    </div>
  );
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  1. 示例 3
ClipboardEvent<T = Element> 剪切板事件对象

DragEvent<T =Element> 拖拽事件对象

ChangeEvent<T = Element> Change事件对象

KeyboardEvent<T = Element> 键盘事件对象

MouseEvent<T = Element> 鼠标事件对象

TouchEvent<T = Element> 触摸事件对象

WheelEvent<T = Element> 滚轮时间对象

AnimationEvent<T = Element> 动画事件对象

TransitionEvent<T = Element> 过渡事件对象

//bivarianceHack 为事件处理函数的类型定义,函数接收一个 event 对象,并且其类型为接收到的泛型变量 E 的类型, 返回值为 void
//关于为何是用bivarianceHack而不是(event: E): void,这与strictfunctionTypes选项下的功能兼容性有关。(event: E): void,如果该参数是派生类型,则不能将其传递给参数是基类的函数。

type EventHandler<E extends React.SyntheticEvent<any>> = {

  bivarianceHack(event: E): void

}['bivarianceHack']

type ReactEventHandler<T = Element> = EventHandler<React.SyntheticEvent<T>>

type ClipboardEventHandler<T = Element> = EventHandler<React.ClipboardEvent<T>>

type DragEventHandler<T = Element> = EventHandler<React.DragEvent<T>>

type FocusEventHandler<T = Element> = EventHandler<React.FocusEvent<T>>

type FormEventHandler<T = Element> = EventHandler<React.FormEvent<T>>

type ChangeEventHandler<T = Element> = EventHandler<React.ChangeEvent<T>>

type KeyboardEventHandler<T = Element> = EventHandler<React.KeyboardEvent<T>>

type MouseEventHandler<T = Element> = EventHandler<React.MouseEvent<T>>

type TouchEventHandler<T = Element> = EventHandler<React.TouchEvent<T>>

type PointerEventHandler<T = Element> = EventHandler<React.PointerEvent<T>>

type UIEventHandler<T = Element> = EventHandler<React.UIEvent<T>>

type WheelEventHandler<T = Element> = EventHandler<React.WheelEvent<T>>

type AnimationEventHandler<T = Element> = EventHandler<React.AnimationEvent<T>>

type TransitionEventHandler<T = Element> = EventHandler<
  React.TransitionEvent<T>
>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

# 七. Types or Interfaces

  1. 巧用 type:
let user = {  name: 'Lucy',  age: 20 }

type User = typeof user;//user{name:string,age:number}
1
2
3
  1. 选择:
  • 在定义公共 API 时(比如编辑一个库)使用interface,这样可以方便使用者继承接口
  • 在定义组件属性(Props)和状态(State)时,建议使用 type,因为 type 的约束性更强
  1. 区别:
  • type 类型不能二次编辑,而 interface 可以随时扩展
type Animal = {
  name: string,
};
// type 类型不支持属性扩展
// Error: Duplicate identifier 'Animal'
type Animal = {
  color: string,
};
//但 interface 能
1
2
3
4
5
6
7
8
9
  • type 可以定义更多类型,interface 只能定义对象

# 八. Props

常用:

type AppProps = {
    status: 'waiting' | 'success'//字面量加联合类型
        obj: {//列出对象的全部属性,这里也可以写个interface
            id: string
            title: string
        }
	  /** array of objects! (common) */
        objArr: {//曾几何时,一度不知道这样写== 数组里面多个对象
            id: string
            title: string
        }[]
      /** 携带点击事件的函数 */
        onClick(event: React.MouseEvent<HTMLButtonElement>): void
      //可选
        onClick?: () => void
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

React 属性:

export declare interface AppBetterProps {

  children: React.ReactNode // 一般情况下推荐使用,支持所有类型 Great

  functionChildren: (name: string) => React.ReactNode

  style?: React.CSSProperties // 传递style对象

  onChange?: React.FormEventHandler<HTMLInputElement>

}

export declare interface AppProps {

  children1: JSX.Element // 差, 不支持数组

  children2: JSX.Element | JSX.Element[] // 一般, 不支持字符串

  children3: React.ReactChildren // 忽略命名,不是一个合适的类型,工具类类型

  children4: React.ReactChild[] // 很好

  children: React.ReactNode // 最佳,支持所有类型 推荐使用

  functionChildren: (name: string) => React.ReactNode // recommended function as a child render prop type

  style?: React.CSSProperties // 传递style对象

  onChange?: React.FormEventHandler<HTMLInputElement> // 表单事件, 泛型参数是event.target的类型

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# 九.