Skip to content

掌握 React TypeScript

前言

TypeScript作为JavaScript的一个超集,主要增加了可选的静态类型支持和基于类的面向对象编程。

对于初次接触TypeScript的开发者来说,可能会觉得编写额外的类型注解是多余的,甚至觉得没有必要。

然而,随着在企业项目中逐渐深入使用TypeScript,你会深刻体会到其类型检查和自动补全功能带来的巨大好处。

一个简单的例子是,当接口中的字段发生更改时,无论是全局替换还是局部替换,都可能会误改其他具有相同字段名称的代码。

如果选择手动替换,当涉及的文件众多时,很容易遗漏某些地方,最终导致bug的产生。

而TypeScript的类型检查功能则可以在编译阶段就捕获这类错误,从而避免潜在的问题。

一、函数组件

  1. 外部声明

使用接口interface定义组件的props类型

tsx
// 使用interface或type
interface AppProps {
  message: string;
}


const App = ({ message }: AppProps) => <div>{message}</div>;
  1. 内联声明

当组件的props中字段较少时,可以直接内联声明

tsx
const App = ({ message }: { message: string }) => <div>{message}</div>;
  1. 使用泛型

使用泛型,可以增强组件props的拓展性

tsx
// 定义泛型
interface Props<T> {
  prop1: T;
  prop2: T;
}


// 定义函数组件
const MyComponent: React.FC<Props<string>> = ({ prop1, prop2 }) => {
  return <div></div>;
};


// prop1,prop2被推断为string类型

二、hooks

  1. useState 类型推断 指定初始值,无需手动定义类型
ts
const [current, setCurrent] = useState(1);

current类型:number

setCurrent类型:Dispatch<React.SetStateAction<number>>

  1. 传入泛型

当初始值为undefined,可以显式指定state的类型

ts
interface User {
  userName: string;
  userId: number;
}


function UserInfo() {
  const [userInfo, setUserInfo] = useState<User | undefined>();
  // userInfo类型为 User 或 undefined
}
  1. 不指定初始值取值问题

当泛型包含undefined时,例如useState<User | undefined>,对象取值时会遇到“对象可能未定义”的校验错误

解决方法1:使用可选链操作符 ?

tsx
function UserInfo() {
  const [userInfo, setUserInfo] = useState<User | undefined>();

  return (
    <div>
      {userInfo?.userName}
    </div>
  );
}

解决方法2:初始值给个空对象,并使用类型断言

ts
const [userInfo, setUserInfo] = useState<User>({} as User);
  1. useCallback

函数的类型根据第一个参数进行推断

  1. useMemo

类型推断 类型根据第一个参数中函数的返回值进行推断

  1. useContext

在使用useContext时,会自动推断出提供的上下文对象的类型,因此类型主要定义在createContext处

传入泛型 将空对象作为默认值,使用类型断言转换为预期的上下文类型

ts
interface UserContextType {
  name: string;
  age: number;
}

const UserContext = createContext<UserContextType>({} as UserContextType);

三、内置类型

1. 样式属性类型

在React中,当想给子组件传递一个style内联样式时,可使用React.CSSProperties

ts
interface Props {
  style?: React.CSSProperties;
}

2. 子元素类型

  1. React.ReactNode

在 JSX 中作为子元素传递的所有可能类型的并集,可以是string,number,也可以是ReactElement,ReactNodeArray

ts
interface Props {
  children?: React.ReactNode;
}
  1. React.ReactElement

只包括 JSX 元素,不包括 JavaScript 原始类型,如 string 或 number。常用来定义函数组件返回值类型

ts
interface Props {
  children?: React.ReactElement;
}

3. 获取组件props类型

如果子组件使用内联类型定义props,而父组件需要子组件props类型时,可使用React.ComponentProps推断子组件的props类型

tsx
function Children({ message }: { message: string }) {
  return (
    <div>
      {message}
      {' '}
    </div>
  );
}

type PropsType = React.ComponentProps<typeof Children>;

四、事件处理

1. event 事件类型

  1. onclick事件

将HTMLButtonElement作为泛型参数传入React.MouseEvent,表示button标签的鼠标事件

ts
interface Props {
  onClick: (event: React.MouseEvent<HTMLButtonElement>) => void;
}
  1. onchange事件

将HTMLInputElement作为泛型参数传入React.ChangeEvent,表示input标签的表单域值变更事件

tsx
function App() {
  const [value, setValue] = useState('');

  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setValue(event.target.value);
  };

  return <input value={value} onChange={handleChange} />;
}
  1. 常用event事件类型
类别事件类型
React.MouseEvent鼠标事件
React.ChangeEventchange事件
React.KeyboardEvent键盘事件
React.DragEvent拖拽事件
React.FocusEvent焦点事件
React.FormEvent表单事件
React.WheelEvent鼠标滚动事件
React.TouchEvent触摸事件
React.ClipboardEvent剪贴板事件
React.AnimationEvent动画事件
React.TransitionEvent过渡事件
  1. HTML标签与类型映射关系

常见的标签及其类型如下:

ts

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. 事件处理函数类型

  1. onchange事件

除了使用Event事件类型,还可以使用React提供的事件处理函数类型,例如上面input的change事件

ts
function handleChange(event: React.ChangeEvent<HTMLInputElement>) {
  setValue(event.target.value);
}

可以写成

ts
const handleChange: React.ChangeEventHandler<HTMLInputElement> = (event) => {
  setValue(event.target.value);
};

Contributors

作者:Long Mo
字数统计:1.2k 字
阅读时长:4 分钟
Long Mo
文章作者:Long Mo
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Longmo Docs