掌握 React TypeScript
前言
TypeScript作为JavaScript的一个超集,主要增加了可选的静态类型支持和基于类的面向对象编程。
对于初次接触TypeScript的开发者来说,可能会觉得编写额外的类型注解是多余的,甚至觉得没有必要。
然而,随着在企业项目中逐渐深入使用TypeScript,你会深刻体会到其类型检查和自动补全功能带来的巨大好处。
一个简单的例子是,当接口中的字段发生更改时,无论是全局替换还是局部替换,都可能会误改其他具有相同字段名称的代码。
如果选择手动替换,当涉及的文件众多时,很容易遗漏某些地方,最终导致bug的产生。
而TypeScript的类型检查功能则可以在编译阶段就捕获这类错误,从而避免潜在的问题。
一、函数组件
- 外部声明
使用接口interface定义组件的props类型
// 使用interface或type
interface AppProps {
message: string;
}
const App = ({ message }: AppProps) => <div>{message}</div>;
- 内联声明
当组件的props中字段较少时,可以直接内联声明
const App = ({ message }: { message: string }) => <div>{message}</div>;
- 使用泛型
使用泛型,可以增强组件props的拓展性
// 定义泛型
interface Props<T> {
prop1: T;
prop2: T;
}
// 定义函数组件
const MyComponent: React.FC<Props<string>> = ({ prop1, prop2 }) => {
return <div></div>;
};
// prop1,prop2被推断为string类型
二、hooks
- useState 类型推断 指定初始值,无需手动定义类型
const [current, setCurrent] = useState(1);
current类型:number
setCurrent类型:Dispatch<React.SetStateAction<number>>
- 传入泛型
当初始值为undefined,可以显式指定state的类型
interface User {
userName: string;
userId: number;
}
function UserInfo() {
const [userInfo, setUserInfo] = useState<User | undefined>();
// userInfo类型为 User 或 undefined
}
- 不指定初始值取值问题
当泛型包含undefined时,例如useState<User | undefined>
,对象取值时会遇到“对象可能未定义”的校验错误
解决方法1:使用可选链操作符 ?
function UserInfo() {
const [userInfo, setUserInfo] = useState<User | undefined>();
return (
<div>
{userInfo?.userName}
</div>
);
}
解决方法2:初始值给个空对象,并使用类型断言
const [userInfo, setUserInfo] = useState<User>({} as User);
- useCallback
函数的类型根据第一个参数进行推断
- useMemo
类型推断 类型根据第一个参数中函数的返回值进行推断
- useContext
在使用useContext时,会自动推断出提供的上下文对象的类型,因此类型主要定义在createContext处
传入泛型 将空对象作为默认值,使用类型断言转换为预期的上下文类型
interface UserContextType {
name: string;
age: number;
}
const UserContext = createContext<UserContextType>({} as UserContextType);
三、内置类型
1. 样式属性类型
在React中,当想给子组件传递一个style内联样式时,可使用React.CSSProperties
interface Props {
style?: React.CSSProperties;
}
2. 子元素类型
- React.ReactNode
在 JSX 中作为子元素传递的所有可能类型的并集,可以是string,number,也可以是ReactElement,ReactNodeArray
interface Props {
children?: React.ReactNode;
}
- React.ReactElement
只包括 JSX 元素,不包括 JavaScript 原始类型,如 string 或 number。常用来定义函数组件返回值类型
interface Props {
children?: React.ReactElement;
}
3. 获取组件props类型
如果子组件使用内联类型定义props,而父组件需要子组件props类型时,可使用React.ComponentProps推断子组件的props类型
function Children({ message }: { message: string }) {
return (
<div>
{message}
{' '}
</div>
);
}
type PropsType = React.ComponentProps<typeof Children>;
四、事件处理
1. event 事件类型
- onclick事件
将HTMLButtonElement作为泛型参数传入React.MouseEvent,表示button标签的鼠标事件
interface Props {
onClick: (event: React.MouseEvent<HTMLButtonElement>) => void;
}
- onchange事件
将HTMLInputElement作为泛型参数传入React.ChangeEvent,表示input标签的表单域值变更事件
function App() {
const [value, setValue] = useState('');
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setValue(event.target.value);
};
return <input value={value} onChange={handleChange} />;
}
- 常用event事件类型
类别 | 事件类型 |
---|---|
React.MouseEvent | 鼠标事件 |
React.ChangeEvent | change事件 |
React.KeyboardEvent | 键盘事件 |
React.DragEvent | 拖拽事件 |
React.FocusEvent | 焦点事件 |
React.FormEvent | 表单事件 |
React.WheelEvent | 鼠标滚动事件 |
React.TouchEvent | 触摸事件 |
React.ClipboardEvent | 剪贴板事件 |
React.AnimationEvent | 动画事件 |
React.TransitionEvent | 过渡事件 |
- HTML标签与类型映射关系
常见的标签及其类型如下:
interface HTMLElementTagNameMap {
a: HTMLAnchorElement;
article: HTMLElement;
aside: HTMLElement;
body: HTMLBodyElement;
br: HTMLBRElement;
button: HTMLButtonElement;
canvas: HTMLCanvasElement;
div: HTMLDivElement;
dl: HTMLDListElement;
dt: HTMLElement;
dd: 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;
iframe: HTMLIFrameElement;
img: HTMLImageElement;
input: HTMLInputElement;
label: HTMLLabelElement;
link: HTMLLinkElement;
main: HTMLElement;
nav: HTMLElement;
p: HTMLParagraphElement;
picture: HTMLPictureElement;
section: HTMLElement;
select: HTMLSelectElement;
span: HTMLSpanElement;
strong: HTMLElement;
table: HTMLTableElement;
tbody: HTMLTableSectionElement;
textarea: HTMLTextAreaElement;
tfoot: HTMLTableSectionElement;
thead: HTMLTableSectionElement;
title: HTMLTitleElement;
tr: HTMLTableRowElement;
ul: HTMLUListElement;
li: HTMLLIElement;
video: HTMLVideoElement;
}
2. 事件处理函数类型
- onchange事件
除了使用Event事件类型,还可以使用React提供的事件处理函数类型,例如上面input的change事件
function handleChange(event: React.ChangeEvent<HTMLInputElement>) {
setValue(event.target.value);
}
可以写成
const handleChange: React.ChangeEventHandler<HTMLInputElement> = (event) => {
setValue(event.target.value);
};