React TypeScript - 将动态泛型类型传递到forwardRef组件中

2024-05-03

我的问题的核心

const FinalComponent<GenericType extends 'a' | 'b'> =tsx 语法无效。

// The 1st line here is invalid tsx syntax
const FinalComponent<InvalidGenericType extends 'a' | 'b'> = 
    forwardRef<HTMLParagraphElement, PropsWithStandardRef<InvalidGenericType>>(({ value }, ref) => {
        return <Component forwardedRef={ref} value={value} />
    }) as ComponentType<InvalidGenericType>

该组件的预期用途:

const ExampleUsage = () => <FinalComponent<'b'> value="b" />

在这种情况下如何创建泛型类型?


额外的背景信息

对于其他上下文,以下是其余代码:

import { Ref, forwardRef } from 'react'

// These are the base props for the component. 
// In terms of usage, these are the props that I care about.
interface Props<GenericType extends 'a' | 'b'> {
    value: GenericType
}

// Adding forwardedRef to the props to define what props are usable inside the component
interface PropsWithForwardRef<GenericType extends 'a' | 'b'> extends Props<GenericType> {
    forwardedRef: Ref<HTMLParagraphElement | null>
}

// Adding standard ref to the props to define what props the component can accept from outside
interface PropsWithStandardRef<GenericType extends 'a' | 'b'> extends Props<GenericType> {
    ref?: Ref<HTMLParagraphElement | null>
}

// forwardRef is interfering with the inheritance of the generic types.
// This is a stand in for the expected return type of the component.
type ComponentType<GenericType extends 'a' | 'b'> = (props: PropsWithStandardRef<GenericType>) => JSX.Element

// The core component code
function CoreComponent<GenericType extends 'a' | 'b'> ({ value, forwardedRef }:PropsWithForwardRef<GenericType>):JSX.Element {
    return <p ref={forwardedRef}>{value}</p>
}

// !!!!!!!!!!! IMPORTANT BIT !!!!!!!!!!!!
// This is where my problem is, I need to be able to pass a dynamic generic type into PropsWithStandardRef and ComponentType.
// I'm not sure how to do that though because `const FinalComponent<InvalidGenericType extends 'a' | 'b'> = forwardRef()` is invalid
const FinalComponent<InvalidGenericType extends 'a' | 'b'> = forwardRef<HTMLParagraphElement, PropsWithStandardRef<InvalidGenericType>>(({ value }, ref) => {

    return <CoreComponent forwardedRef={ref} value={value} />

    // I need the `as ComponentType<InvalidGenericType>` bit because the inferred type that comes out of forwardRef
    // is making TS lose the generic types information
}) as ComponentType<InvalidGenericType>


// This is the end goal of how I want to be able to use this component
// I want to be able to pass a generic type into the component without TS complaining
const ExampleUsage = () => <FinalComponent<'b'> value="b" />

附言。我认识到这个例子有点做作,它是为了简化我的现实世界问题,该问题具有更复杂的组件。


类似但不同的问题

这不同于React Typescript - 动态类型 https://stackoverflow.com/questions/64208371/react-typescript-dynamic-types

在这个问题中,它不需要将类型信息传递到变量中,而只是根据用户提供的值来更改类型。

我需要组件的最终使用才能将类型传递给它。


您提供的代码非常接近工作,但只有一些事情需要更改以确保类型正确性:

  1. 保存 HTML 元素的 Ref 不应该是可变的/可空的,因为它们是由 React 设置和管理的,并且Ref<T>util 已经包含null反正。 (除非你正在做一些真正奇特的事情,比如强制操作渲染树之外的元素......但我什至从未在代码库中看到过这种情况。)因此,我删除了null来自您的工会Ref<HTMLParagraphElement | null>。 (这也会导致将值传递给中的实际段落元素时出现问题CoreComponent.)

  2. 您的返回类型ComponentType需要包括null对于返回类型forwardRef可分配给它。说到返回 React 元素的函数的返回类型,JSX.Element只是一个别名ReactElement with any传入类型参数。我改变了JSX.Element参考ReactElement.

  3. 类型注释仍然可以应用于保存函数表达式值的变量。它的编写方式与任何其他注释的编写方式相同:在标识符名称之后,如下所示:

    const add: (...numbers: number[]) => number = (...nums) => nums.reduce((sum, n) => sum + n, 0);
    

    在我看来,上面的语法不容易阅读,因此我更喜欢将类型括在括号中以提高可读性。您甚至可以使用带有签名的泛型(您的情况需要),并且也可以重载。请参阅FinalComponent在下面的代码中,修改:

import {
  default as React,
  createRef,
  forwardRef,
  ReactElement,
  Ref,
} from 'react';

type AorB = 'a' | 'b';

type Props<T extends AorB> = { value: T };
type PropsWithForwardRef<T extends AorB> = Props<T> & { forwardedRef: Ref<HTMLParagraphElement> };
type PropsWithStandardRef<T extends AorB> = Props<T> & { ref?: Ref<HTMLParagraphElement> };

function CoreComponent<T extends AorB> ({ value, forwardedRef }:PropsWithForwardRef<T>): ReactElement {
  return <p ref={forwardedRef}>{value}</p>;
}

const FinalComponent: (<T extends AorB>(props: PropsWithStandardRef<T>) => ReactElement | null) =
  forwardRef<HTMLParagraphElement, Props<AorB>>(({ value }, ref) => <CoreComponent forwardedRef={ref} value={value} />);

/**
 * The annotation for the function expression above can also be written this way,
 * which allows for overloading with multiple signatures, one on each line inside the braces:
 */
// const FinalComponent: {
//   <T extends AorB>(props: PropsWithStandardRef<T>): ReactElement | null;
// } = forwardRef<HTMLParagraphElement, Props<AorB>>(({ value }, ref) => <CoreComponent forwardedRef={ref} value={value} />);

/* Use: */

const ref = createRef<HTMLParagraphElement>();

const ExampleA = () => <FinalComponent<'a'> value="a" ref={ref} />;
const ExampleB = () => <FinalComponent<'b'> value="b" ref={ref} />;
const RefOptional = () => <FinalComponent<'a'> value="a" />;
const NoRestrictionA = () => <FinalComponent value="a" ref={ref} />;
const NoRestrictionB = () => <FinalComponent value="b" />;

const InvalidA = () => <FinalComponent<'a'> value="b" ref={ref} />;
const InvalidNotAorB = () => <FinalComponent value="c" />;
const InvalidNoValue = () => <FinalComponent<'a'> />;
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

React TypeScript - 将动态泛型类型传递到forwardRef组件中 的相关文章

  • 如何解决此错误“不要使用对象作为类型”?

    我不明白这个错误消息造成的 我的组件有两个和一个包含对象的数据数组 我收到一条错误消息 不要使用object作为一种类型 这object类型目前很难使用 我该如何解决它 我附加了数组包含对象的数据 first tsx import data
  • 如何在ReactJS中定义常量

    我有一个将文本映射到字母的函数 sizeToLetterMap function return small square s large square q thumbnail t small 240 m small 320 n medium
  • 如何将 Twitter 小部件嵌入到 Reactjs 中?

    前往 Twitter 小部件网站 https publish twitter com https publish twitter com 我可以获得一个小部件添加到我的网站 我正在使用示例代码来尝试了解它的工作原理 a class twit
  • React this.state 未定义?

    我正在遵循 Pluralsight 的初学者教程 在表单提交时将值传递给addUser组件方法 我需要将 userName 推送到this state users但我收到错误 App jsx 14 Uncaught TypeError Ca
  • s3 中托管的静态网站:页面刷新后返回 404

    使用此存储桶策略 Version 2012 10 17 Statement Sid PublicReadGetObject Effect Allow Principal Action s3 GetObject Resource arn aw
  • 你如何在react-native中实现捏合缩放?

    我一直在研究 PanResponder 我当前的工作假设是 我将检测是否有两个触摸正在向外移动 如果是 则增加元素大小onPanResponderMove功能 这似乎是一种混乱的方法 有没有更顺畅的方法呢 如果您只需要简单的捏缩放功能 只需
  • 在 TypeScript 中实现类型安全的服务注册表

    我想要一个函数根据给定的标识符 例如字符串或符号 返回对象实例 在代码中它可能看起来像这样 define your services type ServiceA foo gt string const ServiceA foo gt bar
  • MUI DatePicker + date-fns 本地化问题

    当我使用MUI时出现这个问题日期选择器 with 本地化提供商 and 适配器日期Fns with 匈牙利 local
  • React router v6 和路由内页面的相关链接

    您好 我正在尝试使用 React Router 将项目更新到 v6 我了解了基础知识 但在相关链接方面遇到了困难 我们有一个页面 通过 id 呈现给定项目的参考文档 该文档可以使用同级 ID 链接到其他 同级 材料 换句话说 用户可以在文档
  • 为现有模块创建 d.ts 文件

    我正在尝试创建一个d ts文件为React 静态容器 https github com reactjs react static container图书馆 NPM 中安装的库如下所示 var React require react var
  • 在这个反应示例中,bind 做了什么?

    什么是bind在这个声明中做this tick bind 这个 在下面的代码中 export class Counter extends React Component constructor props super props this
  • 使用 React 渲染来自 Express 的 Flash 消息

    我已经搜索了很多 但一直无法找到一种简单的方法来从 Express 获取 Flash 消息并在 React 中渲染它们 我需要访问 Express 服务器上的数据 但是存储这些数据并将其传递给 React 的最佳方式是什么 我正在考虑传递一
  • 在 Chrome 中使用 React 添加新的 DOM 项目不会保持预期的滚动位置

    在 React 中向状态数组添加新项目时 我遇到了一个意外的问题 这会导致更多项目被添加到 DOM 中 在 Safari 和 Firefox 中 这会导致新的 DOM 项目添加到折叠下方 我必须向下滚动才能看到新项目 在 Chrome 中
  • 使用yarn 2工作区在monorepo中的两个项目之间共享打字稿代码

    我想在打字稿中建立一个包含客户端部分 react app 服务器部分 express 和共享库 utils 的项目 我使用yarn 2工作区并希望避免使用larna 如果可能的话 不幸的是 几天以来我一直无法让它工作 并且进行了大量的谷歌搜
  • TypeScript 支持互斥类型吗?

    我有一个带有参数的方法 我希望 TypeScript 验证传入的对象 在编译时 我知道运行时是一种不同的动物 仅满足允许的接口之一 Example interface Person ethnicity string interface Pe
  • 如何在ionic 2中创建覆盖页面?

    当我进入新页面时如何创建透明的引导覆盖页面 我如何在 ionic 2 中实现 您可以在外部创建 div
  • css-loader 不导入 .css 文件返回空对象

    从 css 文件导入样式 返回空对象 看来 css loader 无法正常工作 谁可以帮我这个事 请找到下面的参考文件 index js import React from react import style from header cs
  • 如何更改 Angular Material 选择中的滚动条样式?

    我们需要帮助来更改 Angular Material 的 Select 组件中的滚动条 实现了以下演示 https stackblitz com angular bxbvndrpogl file app 2Fselect reset exa
  • 如何在react-三纤维中提取并播放动画

    嗯 我有 gltf 动画模型 我成功加载模型 但无法播放嵌入的动画 我想知道是否可以以任何方式解决它 顺便说一句 我正在反应中工作 先感谢您 在这里您可以找到型号https drive google com file d 1ZVyklaQu
  • Angular 2 获取当前路线

    所以我需要以某种方式检查我是否在主页上执行某些操作 而在其他页面上则不执行此操作 该组件也在所有页面上导入 如果我在主页上 如何检测该组件 Thanks 尝试这个 import Router from angular router expo

随机推荐