在使用Next.js(React)时要注重类型安全

首先

这篇文章的目的就是提醒大家,在Next.js(React)开发中要重视类型安全。

虽然我们使用 TypeScript,但是最好避免使用 any 等描述,但是在不了解的情况下,也可能不得不妥协。

尽量不要妥协,我们要学习与类型安全相关的知识。

目标读者

使用Next.js(React)和Typescript进行开发的人,不自觉地过多地使用any类型。

文章的结构

如果按照以下的构成,只要牢牢掌握这些要点,我认为类型安全就能得到相当程度的保障,并且会感觉不错。

    1. 使用React.FC将为函数组件提供类型定义。

解释React.ReactNode
对React.ReactNode在children等中的使用进行解释。

使用HTML[○○]Element
通过HTML[○○]Element,可以将其视为对应的HTML元素。

HTML元素属性的类型信息
使用React.ComponentPropsWithoutRef获取HTML元素的属性。

熟练使用实用类型(utility type)
使用实用类型生成新的类型从现有类型。

1. 函数组件的类型定义

在React中,可以使用React.FC来定义函数组件的类型。

然而,由于React能够很好地进行类型推断,因此你可以根据个人喜好决定是否写入这个类型,不写也没问题。

如果要提出一個對於一応型定義記載的好處,那就是

    • 関数コンポーネントであるということが一目でわかる

 

    ジェネリクスを使うことで型情報がまとまってスッキリする

大致就是这样了。

type Props = {
  name: string;
  age: number;
}

const Sample: React.FC<Props> = ({ name, age }) => {
  return <div>{`name: ${name}, age: ${age}`}</div>;
}

2. 关于 React.ReactNode

React.ReactNode 表示了 React 组件可以作为子元素 (children) 接受的类型。

具体例包括组件、字符串、undefined等等…

如果不特别指定children的类型,应该使用React.ReactNode而不是any。

type Props = {
  children: React.ReactNode;
};

const Sample: React.FC<Props> = ({ children }) => {
  return <div>{children}</div>;
};

const Main: React.FC<Props> = () => {
  return (
    <div>
      <Sample>
        <div>sample</div>
      </Sample>
      <Sample>sample</Sample>
    </div>
  );
};

3. 使用HTML[○○]元素

有许多不同的类型,例如HTMLDivElement和HTMLButtonElement,但可以将它们用作表示HTML元素的类型。

例如,当使用forwardRef来处理类似SampleBtn下面的情况时,可以定义HTMLButtonElement 作为要处理的元素的类型。

import { forwardRef } from 'react';

type Props = {
  children: string;
};

const SampleBtn: React.FC<Props> = forwardRef<HTMLButtonElement, Props>(({ children }, ref) => {
  return <button ref={ref}>{children}</button>;
});

4. HTML元素的属性类型信息

可以使用React.ComponentPropsWithoutRef或React.ComponentPropsWithRef来获取HTML元素属性的类型信息。
区别在于是否包含Ref字样的名称。

type Props = { children: React.ReactNode } & React.ComponentPropsWithoutRef<'button'>;

const SampleBtn: React.FC<Props> = ({ children, ...buttonAttributes }) => {
  return <button {...buttonAttributes}>{children}</button>;
};

export const Main = () => {
  return (
    <div>
      {/* button要素の属性をすべて受け付けるので、typeが設定可能 */}
      <SampleBtn type='button'>button</SampleBtn>
    </div>
  );
};

5. 熟练运用“实用型”技能

通过使用utility types,可以重用类型,使源代码更易于维护。

我认为常常使用的是Pick和Omit等等,可以通读一遍,以便随时准备使用。

如果你对以下内容感兴趣,请点击链接查看原文。

所需的

以下是公式。

Required是一个从T的所有属性中删除?的可选项的实用工具类型。

image.png

只读的

以下是公式。

Readonly是一个实用类型,用于将对象类型T的所有属性都设置为只读。

image.png

泛型T的部分

这里有一个公式。

Partial是一种实用类型,它将类型T的所有属性转换为可选属性。

image.png

选择<T, Keys>

以下是公式。

Pick是一个实用类型,它返回一个只包含指定键Keys的对象类型,该对象类型是从类型T派生的。

image.png

省略<T, Keys>

这是公式。

Omit是一个实用类型,它返回从对象类型T中排除了Keys指定属性的object类型。

image.png

排除 <T, U>

这里是公式。

Exclude是一个实用类型,它从联合类型T中删除指定类型U,并返回一个新的联合类型。

image.png

提取<T, U>

公式在这里。

Extract是一个实用型,它从联合类型T中提取出仅由类型U指定的类型返回。

image.png

让我们自定义上述的实用工具类型。

在中文中,我们很少直接使用 Required\ 或 Readonly\,通常只会用于需要将某个属性设为必需的情况。

在这种情况下,需要根据情况自定义实用程序类型。

我想要巧妙地利用现有的模板,以追求一个具有一致性的源代码!

type AddRequired<T, U extends keyof T> = Omit<T, U> & Required<Pick<T, U>>;

type BaseProps = {
  children: React.ReactNode;
  disabled: boolean;
};

type Props = AddRequired<BaseProps, 'children'>;

结束

使用TypeScript的话,尽量避免使用any,并且努力实现类型安全的实现。

我認為這關乎品質問題,所以我會堅持不妥協,繼續努力學習!

广告
将在 10 秒后关闭
bannerAds