TypeScript 泛型与函数式 React 组件的协同作用

前言

在本文中,我们将探讨 TypeScript 泛型和函数式 React 组件之间强大的协同作用。

泛型允许您定义灵活的组件,这些组件可以适应不同的数据结构并在整个代码库中强制执行类型安全。

通过在功能组件中利用泛型,您可以创建高度可重用且适应性强的 UI 元素,这些元素可以无缝处理不同的数据需求。

在本教程中,我们将首先了解 TypeScript 中泛型的概念以及它们如何在 React 开发环境中发挥作用。

然后我们将深入研究实际示例,演示如何使用 TypeScript 在 React 中定义通用功能组件。

我们还将讨论通用 props 发挥作用的各种用例,使我们能够构建通用且可扩展的 React 应用程序。federico-beccari-ahi73ZN5P0Y-unsplash

TypeScript 中的泛型是什么?

为了探索带有泛型的函数组件,您需要掌握 TypeScript 中泛型函数的基础知识——包括它们的定义和实现。

在本节中,您将简要概述什么是泛型以及如何在 TypeScript 中实现它们。这应该为您提供必要的知识,以便更深入地研究功能组件领域。

如何在 TypeScript 中声明泛型函数

<T>要在 TypeScript 中声明泛型函数,我们在函数签名的开头放置一个泛型类型参数,表示为。这<T>表示使用函数时将传递的类型。它充当将在运行时确定的特定类型的占位符,类似于常规函数中参数的行为方式。

例如,考虑以下函数:

function func<T>(value: T):T[] {
   return [value];
}

func('Hello John');

在此示例中,泛型类型参数T用于表示值参数和返回类型将是相同的类型。

func使用参数调用该函数时'Hello John', for 的推断类型T将变为string。因此,该函数的返回类型为string[],表示将返回一个包含所提供字符串值的数组。

如何在 TypeScript 中使用箭头函数定义泛型

使用箭头函数定义泛型函数的语法与我们之前看到的函数声明的语法略有不同:  

export const func = <T>(value: T):T[] => {
   return [value];
}

func('Hello John');

从上面我们可以看出,在 TypeScript 中使用箭头函数定义泛型函数时,我们使用<T>参数列表前面的语法来表示泛型类型参数。

接下来,需要注意的是,T前面示例中使用的泛型类型参数只是一个描述性名称,可以替换为任何其他有效标识符。例如:

export const func = <K>(value: K):K[] => {
   return [value];
}

func('Hello John');

泛型类型参数T已替换为K,这表明泛型类型的名称选择是灵活的,并且可以进行自定义以匹配上下文或开发人员偏好。

该函数func仍然是通用的,能够接受使用过程中指定的任何类型并返回相同类型的数组。

现在您已经知道如何实现泛型函数并了解它们在返回任何传递类型时的灵活性,我们现在将学习如何在 React 中实现泛型组件。

在下一节中,我将逐步介绍如何创建和使用通用组件。这将帮助您在 React 开发中利用泛型的力量。

如何在 React 中定义和使用通用组件

就像泛型函数一样,您可以通过集成 TypeScript 泛型来设计泛型组件,从而将组件的可重用性提升到一个新的水平。

声明通用组件将接受的通用 props 是设计组件的第一步。我们可以使用 TypeScript 泛型构建一个支持不同数据类型的参数化 props 接口。

interface MyComponentProps<T> {
  data: T;
  // Add additional props specific to your component
}

一旦定义了通用 props 接口,您就可以实现通用组件本身。这涉及使用声明的通用属性并将它们集成到组件的结构中。

与上一节中的 TypeScript 函数描述类似,它具有相同的实现。

function MyComponent<T>({ data }: MyComponentProps<T>) {

  return (
    <div>
      {/* JSX content */}
    </div>
  );
}

接下来,您还可以使用箭头函数语法定义通用组件。但当您在文件中编写代码时,情况会有所不同JSX.Element

为了避免泛型类型参数和jsx组件之间出现歧义,您可以在类型参数中添加尾随逗号以将其与JSX.Element. 例如:

interface MyComponentProps<T> {
  data: T;
}
// notice the trailing comma after <T
const MyComponent = <T,>({ data }: MyComponentProps<T>) => {
  return (
  <div>{JSX content}</div>;
  )
};
export default MyComponent;

通用组件的示例用例

假设您想要开发一个数据可视化仪表板,能够呈现来自不同来源的数据,每个来源都有其独特的结构和属性。但您希望创建一个可重用的组件,它可以生成任何数据对象的摘要,重点关注特定属性。

此场景提供了深入研究 React 中通用组件的实际应用的机会。

通过将类型参数扩展为并在接口中object使用运算符,您可以构造一个既提供灵活性又提供类型安全的组件。keyof

这种方法利用 TypeScript 强大的类型系统的功能,使您能够无缝地处理各种对象。

要实现此目的,请定义一个名为 的通用组件,该组件接受扩展对象的Summary<T>类型参数。T您还将使用keyof运算符来指定要在摘要中显示的对象的属性:

interface SummaryProps<T extends object, K extends keyof T> {
  data: T;
  property: K;
}

export function Summary<T extends object, K extends keyof T>({
  data,
  property,
}: SummaryProps<T, K>) {
  const value = data[property] as string;

  return (
    <div>
      {(typeof property === "string") ? (
        <p>
          {property}: {value}{" "}
        </p>
      ) : (
        ""
      )}
    </div>
  );
}

Summary组件中,我们定义了一个T扩展的泛型类型参数object,确保传递给组件的数据是一个object类型。

第二个类型参数K使用keyof T符号,表明它必须是对象类型的键T。这样,您可以根据提供的属性值访问数据对象的特定属性。

在组件内,我们object使用property作为键从数据中提取值。为了确保该值被视为 a string,我们使用as关键字来执行类型断言:data[property] as string以避免赋值错误。此类型断言告诉 TypeScript 将值视为string.

然后,该组件返回一个<div>包含元素的条件呈现的元素<p>。然后代码检查 是否属于使用 的property类型。这样也可以防止赋值错误。stringtypeof property === "string"

如果其计算结果为true,则代码将呈现该<p>元素,并显示propertyvaluestring否则,将返回空值。

定义组件后,让我们考虑一个示例,其中有两个不同的数据源:UserProduct。每个数据源都有其自己的属性,但您希望根据特定属性显示摘要。

您可以首先定义表示用户数据的接口,指定、和 等User属性。同样,创建接口来表示产品数据,包括、和 等属性,如下所示:idnameemailProductidnameprice

interface User {
  id: number;
  name: string;
  email: string;
}

interface Product {
  id: number;
  name: string;
  price: number;
}

接下来,您可以创建这些数据对象的实例。例如,userDatacan 代表 auserproductDatacan 代表 a product,它们各自的属性填充有示例数据:

interface User {
  id: number;
  name: string;
  email: string;
}

interface Product {
  id: number;
  name: string;
  price: number;
}

要使用该Summary组件,请为其提供不同的数据源并指定要在摘要中显示的属性。

例如,您可以使用<Summary<User, "name">>来呈现用户名的摘要,并<Summary<Product, "price">>显示产品的价格:

const userData: User = {
  id: 1,
  name: "John Doe",
  email: "johndoe@example.com"
};

const productData: Product = {
  id: 1,
  name: "Smartphone",
  price: 999
};

完整的代码如下所示:

interface User {
  id: number;
  name: string;
  email: string;
}

interface Product {
  id: number;
  name: string;
  price: number;
}

const userData: User = {
  id: 1,
  name: "John Doe",
  email: "johndoe@example.com"
};

const productData: Product = {
  id: 1,
  name: "Smartphone",
  price: 999
};

// Usage of Summary component with different data sources and properties
<Summary<User, "name"> data={userData} property="name" />
<Summary<Product, "price"> data={productData} property="price" />

TypeScript 强大的类型推断机制在这种情况下就发挥了作用。当您向组件提供data和时,TypeScript 确保指定的属性对于相应的数据源有效。propertySummary

如果您错误地尝试使用无效属性(例如提供"email"为数据的属性)Product,TypeScript 编译器将引发类型错误。这确保了类型安全并有助于防止潜在的运行时问题。

通过利用 TypeScript 的静态类型检查,我们在使用Summary. 这也有助于在开发过程的早期发现错误,并确保提供的dataproperty组合是正确的。

结论

在本指南中,我们探讨了 TypeScript 中泛型的概念,以及如何应用它们在 React 中创建强大且可重用的组件。

泛型允许我们定义足够灵活的组件来处理各种数据类型,同时保持类型安全。

在本文中,您学习了泛型基础知识,包括泛型函数的实现。然后,我们深入研究了 React 中通用组件的世界,演示了如何使用arrownamed函数方法来定义和实现它们。

当您继续使用 TypeScript 的旅程时,我鼓励您进一步探索通用 props 的强大功能和灵活性。通过利用泛型,您可以解锁创建可重用且类型安全的组件的新可能性,从而为您的 React 应用程序提供支持。

© 版权声明
THE END
喜欢就支持一下吧
点赞15 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容