一、函数组件
1. 外部声明
js
//使用interface或type
interface AppProps {
message: string;
}
const App = ({ message }: AppProps) => <div>{message}</div>;
2. 内联声明
js
const App = ({ message }: { message: string }) => <div>{message}</div>;
3. 使用泛型
js
// 定义泛型
interface Props<T> {
prop1: T;
prop2: T;
}
// 定义函数组件
const MyComponent: React.FC<Props<string>> = ({ prop1, prop2 }) => {
return <div></div>;
};
//prop1,prop2被推断为string类型
二、hooks
1. useState
1. 类型推断
指定初始值,无需手动定义类型
js
const [current, setCurrent] = useState(1);
current类型:number
setCurrent类型:Dispatch<React.SetStateAction<number>>
2. 传入泛型
显式指定state的类型
js
interface User{
userName:string,
userId:number,
}
function UserInfo() {
const [userInfo, setUserInfo] = useState<User | undefined>();
//userInfo类型为 User 或 undefined
}
3. 不指定初始值取值问题
当泛型包含undefined时,例如useState<User | undefined>,对象取值时会遇到"对象可能未定义"的校验错误
解决方法1:使用可选链操作符 ?
js
function UserInfo() {
const [userInfo, setUserInfo] = useState<User | undefined>();
return (
<div>
{userInfo?.userName}
</div>
);
}
解决方法2:初始值给个空对象,并使用类型断言
js
const [userInfo, setUserInfo] = useState<User>({} as User);
2. useCallback
函数的类型根据第一个参数进行推断
js
const memoizedCallback = useCallback((param1: string, param2: number) => {}, []);
memoizedCallback类型被推断为:
js
(param1: string, param2: number) => void
3. useMemo
1. 类型推断
类型根据第一个参数中函数的返回值进行推断
js
const str = useMemo(() => 1 + "2", []); //str类型被推断为string
2. 传入泛型
显式指定返回值的类型
js
const str = useMemo<number>(() => 1 + "2", []); //报错:不能将类型"string"分配给类型"number"
4. useRef
1. 用来访问DOM节点
给一个初始值null
js
const divRef = useRef<HTMLDivElement>(null);
2. 用来清除定时器
js
const intervalRef = useRef<NodeJS.Timer>();
useEffect(() => {
intervalRef.current = setInterval(() => {
console.log("打印");
}, 200);
return () => clearInterval(intervalRef.current);
}, []);
5. useImperativeHandle
类型定义在forwardRef处,在forwardRef中指定props与ref的类型
注意:这里泛型参数传递的参数顺序,ref 在前,props在后
js
import { useRef, forwardRef, useImperativeHandle, useState } from "react";
//定义ref类型
interface ForwardObject {
reset: () => void;
}
const App = () => {
//给一个初始值null
const countRef = useRef<ForwardObject>(null);
const handleClick = () => {
countRef.current?.reset();
};
return (
<div>
<Count ref={countRef} />
<button onClick={handleClick}>重置</button>
</div>
);
};
//注意:props,ref类型定义的顺序是反的
const Count = forwardRef<ForwardObject,unknown>((props, ref) => {
const [count, setCount] = useState(0);
useImperativeHandle(ref, () => ({
reset: handleReset,
}));
const handleReset = () => {
setCount(0);
};
return (
<div>
{count}
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
});
export default App;
6. useContext
在使用useContext时,会自动推断出提供的上下文对象的类型,因此类型主要定义在createContext处
1. 类型推断
指定初始值,无需手动定义类型
js
const UserContext = createContext({
name: "张三",
age: 20,
});
UserContext推断为
js
const UserContext: React.Context<{
name: string;
age: number;
}>
2. 传入泛型
将空对象作为默认值,使用类型断言转换为预期的上下文类型
js
interface UserContextType {
name: string;
age: number;
}
const UserContext = createContext<UserContextType>({} as UserContextType);
7. useReducer
两处类型定义:
-
使用 typeof 推断初始值state类型
-
使用联合类型定义reducer的action类型
js
import { useReducer } from "react";
const initialCount = {
count: 0,
};
//1.定义初始值类型
type State = typeof initialCount;
//2.定义action类型
type ActionType = { type: "increment" } | { type: "decrement" };
function reducer(state: State, action: ActionType) {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
case "decrement":
return { count: state.count - 1 };
default:
throw new Error();
}
}
const App = () => {
const [state, dispatch] = useReducer(reducer, initialCount);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({ type: "decrement" })}>-</button>
<button onClick={() => dispatch({ type: "increment" })}>+</button>
</>
);
};
export default App;
8. useEffect / useLayoutEffect
useEffect与useLayoutEffect都用于执行副作用,不需要手动定义类型
三、内置类型
1. 样式属性类型
在React中,当想给子组件传递一个style内联样式时,可使用React.CSSProperties
js
interface Props{
style?:React.CSSProperties
}
2. 子元素类型
1. React.ReactNode
在 JSX 中作为子元素传递的所有可能类型的并集,可以是string,number,也可以是ReactElement,ReactNodeArray
js
interface Props{
children?: React.ReactNode;
}
2. React.ReactElement
只包括 JSX 元素,不包括 JavaScript 原始类型,如 string 或 number。常用来定义函数组件返回值类型
js
interface Props{
children?: React.ReactElement;
}
3. 获取组件props类型
如果子组件使用内联类型定义props,而父组件需要子组件props类型时,可使用React.ComponentProps推断子组件的props类型
js
const Children = ({ message }: { message: string }) => <div>{message}</div>;
type PropsType = React.ComponentProps<typeof Children>;
PropsType类型为
js
type PropsType = {
message: string;
}
四、事件处理
1. event 事件类型
1. onclick事件
将HTMLButtonElement作为泛型参数传入React.MouseEvent,表示button标签的鼠标事件
js
interface Props{
onClick:(event:React.MouseEvent<HTMLButtonElement>)=>void
}
2. onchange事件
将HTMLInputElement作为泛型参数传入React.ChangeEvent,表示input标签的表单域值变更事件
js
function App() {
const [value, setValue] = useState("");
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setValue(event.target.value);
};
return <input value={value} onChange={handleChange} />;
}
3. 常用event事件类型
情况 | 类别 |
---|---|
React.MouseEvent | 鼠标事件 |
React.ChangeEvent | change事件 |
React.keyboardEvent | 键盘事件 |
React.DragEvent | 拖拽事件 |
React.FocusEvent | 焦点事件 |
React.FormEvent | 表单事件 |
React.WheelEvent | 鼠标滚动事件 |
React.TouchEvent | 触摸事件 |
React.ClipboardEvent | 剪贴板事件 |
React.AnimationEvent | 动画事件 |
React.TransitionEvent | 过渡事件 |
4. HTML标签与类型映射关系
常见的标签及其类型如下:
js
interface HTMLElementTagNameMap {
"a": HTMLAnchorElement;
"article": HTMLElement;
"aside": HTMLElement;
"audio": HTMLAudioElement;
"body": HTMLBodyElement;
"br": HTMLBRElement;
"button": HTMLButtonElement;
"canvas": HTMLCanvasElement;
"caption": HTMLTableCaptionElement;
"code": HTMLElement;
"col": HTMLTableColElement;
"colgroup": HTMLTableColElement;
"dd": HTMLElement;
"del": HTMLModElement;
"dialog": HTMLDialogElement;
"div": HTMLDivElement;
"dl": HTMLDListElement;
"dt": HTMLElement;
"em": HTMLElement;
"footer": HTMLElement;
"form": HTMLFormElement;
"h1": HTMLHeadingElement;
"h2": HTMLHeadingElement;
"h3": HTMLHeadingElement;
"h4": HTMLHeadingElement;
"h5": HTMLHeadingElement;
"h6": HTMLHeadingElement;
"head": HTMLHeadElement;
"header": HTMLElement;
"html": HTMLHtmlElement;
"i": HTMLElement;
"iframe": HTMLIFrameElement;
"img": HTMLImageElement;
"input": HTMLInputElement;
"label": HTMLLabelElement;
"legend": HTMLLegendElement;
"li": HTMLLIElement;
"link": HTMLLinkElement;
"main": HTMLElement;
"map": HTMLMapElement;
"mark": HTMLElement;
"menu": HTMLMenuElement;
"meta": HTMLMetaElement;
"meter": HTMLMeterElement;
"nav": HTMLElement;
"ol": HTMLOListElement;
"option": HTMLOptionElement;
"p": HTMLParagraphElement;
"picture": HTMLPictureElement;
"progress": HTMLProgressElement;
"script": HTMLScriptElement;
"section": HTMLElement;
"select": HTMLSelectElement;
"small": HTMLElement;
"source": HTMLSourceElement;
"span": HTMLSpanElement;
"strong": HTMLElement;
"style": HTMLStyleElement;
"sub": HTMLElement;
"table": HTMLTableElement;
"tbody": HTMLTableSectionElement;
"template": HTMLTemplateElement;
"textarea": HTMLTextAreaElement;
"tfoot": HTMLTableSectionElement;
"thead": HTMLTableSectionElement;
"time": HTMLTimeElement;
"title": HTMLTitleElement;
"tr": HTMLTableRowElement;
"track": HTMLTrackElement;
"u": HTMLElement;
"ul": HTMLUListElement;
"video": HTMLVideoElement;
}
2. 事件处理函数类型
1. onchange事件
除了使用Event事件类型,还可以使用React提供的事件处理函数类型,例如上面input的change事件
js
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setValue(event.target.value);
};
可以写成
js
const handleChange: React.ChangeEventHandler<HTMLInputElement> = (event) => {
setValue(event.target.value);
};
event事件对象被自动推断为:React.ChangeEvent<HTMLInputElement>
类型
2. 常用事件处理函数类型
情况 | 类别 |
---|---|
React.MouseEventHandler | 鼠标事件 |
React.ChangeEventHandler | change事件 |
React.KeyboardEventHandler | 键盘事件 |
React.DragEventHandler | 拖拽事件 |
React.FocusEventHandler | 焦点事件 |
React.FormEventHandler | 表单事件 |
React.WheelEventHandler | 鼠标滚动事件 |
React.TouchEventHandler | 触摸事件 |
React.ClipboardEventHandler | 剪贴板事件 |
React.AnimationEventHandler | 动画事件 |
React.TransitionEventHandler | 过渡事件 |
五、工具泛型
Typescript提供的工具泛型能提高类型的复用率,减少很多类型定义,这里列举一些常用的
1. Partial<T>
将所有属性都变为可选属性
js
interface Person{
name: string;
age: number;
}
type PersonPartial = Partial<Person>;
/**
* type PersonPartial = {
* name?: string;
* age?: number;
* }
*/
2. Required<T>
将所有可选属性都变为必选属性
js
interface Props {
a?: number;
b?: string;
};
const obj: Props = { a: 5 }; // OK
const obj2: Required<Props> = { a: 5 }; // Error: property 'b' missing
3. Readonly<T>
将所有属性都变为只读属性
js
type ReadonlyPerson = Readonly<Person>;
4. Pick<T,K>
选取部分属性
js
interface Todo {
title: string;
description: string;
done: boolean;
}
type TodoBase = Pick<Todo, "title" | "done">;
// =
type TodoBase = {
title: string;
done: boolean;
};
5. Omit<T,K>
去除部分属性,适合接口
js
interface User {
id: string;
name: string;
email: string;
};
type UserWithoutEmail = Omit<User, "email">;
// UserWithoutEmail ={id: string;name: string;}
6. Record<T,K>
定义一个对象的key和value类型
js
Record<string,any>
//等价于
{
[key: string]: any;
}
js
interface PageInfo {
title: string;
}
type Page = 'home' | 'about' | 'contact';
const x: Record<Page, PageInfo> = {
about: { title: 'about' },
contact: { title: 'contact' },
home: { title: 'home' },
};
7. Exclude<T,U>
剔除某些类型成员,适用于字面量类型
js
type A = 'get' | 'put' | 'post';
type B = Exclude<A, 'get' | 'post'>; //type B = "put"
8. Extract<T,U>
提取某些属性,适用于联合类型
js
type MyUnion = 'a' | 'b' | 'c' | 'd';
type Extracted = Extract<MyUnion, 'a' | 'c'>;
// 提取出 'a' 和 'c',得到类型 'a' | 'c'
9. ReturnType<T>
获取函数的返回值类型
js
function test(name:string,idx:number){
return {
name,idx
}
}
type A = typeof test;
//type A = (name: string, idx: number) => {
// name: string;
// idx: number;
// }
type TestReturnType = ReturnType<typeof test>
// type TestReturnType = {
// name: string;
// idx: number;
// }
10. Parameters<T>
获取函数类型的参数类型
js
function test(name:string,idx:number){
return {
name,idx
}
}
type TestArgsType = Parameters<typeof test>
//type TestArgsType = [name: string, idx: number]
11. NonNullable<T>
剔除 null 和 undefined 类型
js
type NullableString = string | null | undefined;
type NonNullableString = NonNullable<NullableString>;
// NonNullableString 的类型为 string