自从给 React 组件用上 Typescript之后,太爽了!

2022-07-29 08:09:20 浏览数 (1)

1. 为什么要给React组件类型 ?

如果你在编写中型和大型的web应用程序,TypeScript很有用。注释变量、对象和函数在应用程序的不同部分之间创建了契约。

例如,假设我是一个在屏幕上显示格式化日期的组件的作者。

代码语言:javascript复制
interface FormatDateProps {
  date: Date
}

function FormatDate({ date }: FormatDateProps): JSX.Element {
  return <div>{date.toLocaleString()}</div>;
}

根据FormatDateProps接口,组件FormatDate date prop的值只能是date的一个实例。这是一个约束条件。

为什么这个约束很重要?因为FormatDate组件在日期实例上调用方法date. tolocalestring(),并且日期prop必须是一个日期实例。否则组件将无法工作。

那么FormatDate组件的用户就必须满足这个约束,并且只提供date实例:

代码语言:javascript复制
<FormatDate
  date={new Date()}
/>

如果用户忘记了约束,例如提供一个字符串“Sep 28 2021”到日期prop:

代码语言:javascript复制
<FormatDate
  date="Sep 28 2021"
  Type 'string' is not assignable to type 'Date'.
/>

那么TypeScript就会显示一个类型错误。

这很好,因为错误是在开发过程中捕获的,而不是隐藏在代码库中。

2. 约束 props

在我看来,React从TypeScript获得的最大好处是支持类型。

输入React组件通常需要两个步骤。

  1. 定义接口,描述组件使用对象类型接受什么 props。一个很好的props接口命名约定是ComponentName props = ComponentNameProps
  2. 使用接口标注功能组件功能内部的 props 参数。

例如,让我们注释一个接受两个props的组件Message: text(一个字符串)和important(一个布尔值):

代码语言:javascript复制
interface MessageProps {
  text: string;
  important: boolean;
}

function Message({ text, important }: MessageProps) {
  return (
    <div>
      {important ? 'Important message: ' : 'Regular message: '}
      {text}
    </div>
  );
}

MessageProps是描述组件接受的props的接口:text 是字符串类型,important 的是 boolean 类型。

现在,当渲染组件时,你必须根据 props 类型设置 props 的值:

代码语言:javascript复制
<Message
  text="The form has been submitted!"
  important={false}
/>

2.1 Props 验证

现在,如果你碰巧为组件提供了错误的props值类型,那么TypeScript会在编译时警告你错误的props值。

通常,错误是在以下阶段捕获的——类型检查、单元测试、集成测试、端到端测试、来自用户的错误报告——越早捕获错误越好!

如果Message组件呈现一个无效的prop值:

代码语言:javascript复制
<Message
  text="The form has been submitted!"
  important={0}
Type 'number' is not assignable to type 'boolean'.
/>

或者没有 prop:

代码语言:javascript复制
<Message
Property 'text' is missing in type '{ important: true; }' but required in type 'MessageProps'.
  important={true}
/>

然后TypeScript会发出警告。

2.2 children prop

children是React组件中的一个特殊prop:当组件被渲染时,它保存了开始和结束标记之间的内容:

代码语言:javascript复制
<Component>children</Component>

children prop 的内容大多是JSX元素,可以使用特殊类型JSX进行键入。元素(在React环境中全局可用的类型)。

让我们稍微更改Message组件以使用子组件prop:

代码语言:javascript复制
interface MessageProps {
  children: JSX.Element | JSX.Element[];
  important: boolean;
}

function Message({ children, important }: MessageProps) {
  return (
    <div>
      {important ? 'Important message: ' : 'Regular message: '}
      {children}
    </div>
  );
}

看看接口中的 children prop:它接受单个元素JSX.Element或JSX.Element[]的数组。

现在你可以使用Jsx.Element 作为子元素来表示消息:

代码语言:javascript复制
<Message important={false}>
  <span>The form has been submitted!</span>
</Message>

或者多个子元素:

代码语言:javascript复制
<Message important={false}>
  <span>The form has been submitted!</span>
  <span>Your request will be processed.</span>
</Message>

2.3 可选的 props

要使props 接口中的prop可选,用一个特殊的符号符号 ?

例如,让我们将重要的prop标记为可选的:

代码语言:javascript复制
interface MessageProps {
  children: JSX.Element | JSX.Element[];
  important?: boolean;
}

function Message({ children, important = false }: MessageProps) {
  return (
    <div>
      {important ? 'Important message: ' : 'Regular message: '}
      {children}
    </div>
  );
}

在MessageProps界面中,important prop被标记为?——important?Boolean , 即该 prop 可选。

在Message函数中,我还为的important 的 prop: {children, important = false}添加了一个false默认值。如果没有指定值,这将是默认值。

现在TypeScript允许你跳过important 的 prop:

代码语言:javascript复制
<Message>
  <span>The form has been submitted!</span>
</Message>

3. Return type

在前面的示例中,Message函数没有显式地指示其返回类型。这是因为TypeScript很智能,可以推断出函数的返回类型——JSX.Element:

代码语言:javascript复制
type MessageReturnType = ReturnType<typeof Message>;

type MessageReturnType = JSX.Element

我的建议是强制每个函数显式地指示返回类型。这样做可以发现许多愚蠢的错误和拼写错误。

在React函数组件的情况下,返回类型通常是JSX.Element:

代码语言:javascript复制
function Message({ 
    children, 
    important = false 
  }: MessageProps): JSX.Element {
  return (
    <div>
      {important ? 'Important message: ' : 'Regular message: '}
      {children}
    </div>
  );
}

在某些情况下,组件可能不返回任何内容。如果是这种情况,就使用联合JSX.Element | null 作为返回类型:

代码语言:javascript复制
interface ShowTextProps {
  show: boolean;
  text: string;
}

function ShowText({ show, text }: ShowTextProps): JSX.Element | null {
  if (show) {
    return <div>{text}</div>;
  }
  return null;
}

如果show prop为真,ShowText返回一个元素,否则返回null。这就是为什么ShowText函数的返回类型是一个联合JSX.Element。

总结

React组件可以从TypeScript中受益匪浅。

给组件规定类型对于验证组件的支持非常有用。通常,这是通过定义一个接口来实现的,每个prop都有自己的类型。

然后,当带注释的组件呈现时,TypeScript会验证是否提供了正确的prop值。

在数据验证的基础上,类型可以作为元信息的重要来源,提供注释函数或变量如何工作的线索。

0 人点赞