# 前言
记录 eact 开发中常见类型定义。以下类型定义在不同的版本中可能会有报错。
# 一. 类组件
- 主要定义为:
React.PureComponent<P,S,SS>
P 是 props 的类型,S 是 state 的类型(可不定义,state的类型会自己推断),SS是getSnapshotBeforeUpdate返回值。
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
2
3
4
5
6
7
8
9
10
11
12
13
14
# 二. 函数组件
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
2
3
4
5
6
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
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
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
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
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
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的类型,第一个T是ref的类型,P是props的类型。
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
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
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
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
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
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
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
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
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
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
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
2
3
4
5
6
7
8
9
10
11
# 六. 事件处理
- 示例 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
- 示例 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- 示例 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
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
- 巧用 type:
let user = { name: 'Lucy', age: 20 }
type User = typeof user;✅//user{name:string,age:number}
1
2
3
2
3
- 选择:
- 在定义公共 API 时(比如编辑一个库)使用
interface,这样可以方便使用者继承接口 - 在定义组件属性(
Props)和状态(State)时,建议使用 type,因为type的约束性更强
- 区别:
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
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
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
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