通用无状态组件 React 的类型?或在打字稿中扩展通用函数接口以具有进一步的通用性?

     2023-02-21     13

关键词:

【中文标题】通用无状态组件 React 的类型?或在打字稿中扩展通用函数接口以具有进一步的通用性?【英文标题】:Type of Generic Stateless Component React? OR Extending generic function interface in typescript to have a further generic? 【发布时间】:2018-12-29 19:04:20 【问题描述】:

问题Stateless Functional Component的接口为

interface SFC<P = > 
    (props: P &  children?: ReactNode , context?: any): ReactElement<any> | null;
    propTypes?: ValidationMap<P>;

我的组件的 prop 类型也是通用的:

interface Prop<V>
    num: V;

如何正确定义我的组件?如:

const myCom: <T>SFC<Prop<T>> = <T>(props: Prop<T>)=> <div>test</div>

character 27 给出错误Cannot find name 'T'

这里是:Typescript Playground of modified example

我的发现

1:Typescript 2.9.1 支持有状态的通用组件:http://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-9.html#generic-type-arguments-in-jsx-elements

class myCom<T> extends React.Component<Prop<T>, any> 
   render() 
      return <div>test</div>;
   

2:扩展SFC 以创建一个新接口,如以下答案中所述,将使组件的道具类型为any: Typescript React stateless function with generic parameter/return types 我不想要。我想为我的道具提供正确的类型

【问题讨论】:

如果将通用的&lt;T&gt; 替换为&lt;T extends &gt; 会发生什么? 同样的错误。正如我想要的那样:const myCom: &lt;T&gt;SFC&lt;Prop&lt;T&gt;&gt; 我在描述@JonasW 中添加了游乐场链接。 @NamanKheterpal 我遇到了同样的问题并为此调查了一些时间。你可以找到我的解决方案,如何声明以及如何使用 React SFC here 【参考方案1】:

你不能像这样使用泛型:

const myCom: <T>SFC<Prop<T>> = <T>(props: Prop<T>)=> <div>test</div>

TypeScript 规范指出:

表单的构造

< T > ( ... ) =>  ... 

可以解析为带有类型参数的箭头函数表达式或应用于不带类型参数的箭头函数的类型断言。

source; Microsoft/TypeScript spec.md

您的声明与 TypeScript 规范中定义的模式不匹配,因此它不起作用。

但是,您可以不使用 SFC 接口而只自己声明它。

interface Prop<V> 
    num: V;


// normal function
function Abc<T extends string | number>(props: Prop<T>): React.ReactElement<Prop<T>> 
    return <div />;


// const lambda function
const Abc: <T extends string | number>(p: Prop<T>) => React.ReactElement<Prop<T>> = (props) => 
   return <div />
;

export default function App() 
    return (
        <React.Fragment>
            <Abc<number> num=1 />
            <Abc<string> num="abc" />
            <Abc<string> num=1 /> // string expected but was number
        </React.Fragment>
    );

【讨论】:

如果您与React.FC 有交集类型,是否可以以某种方式使用此模式?例如,我希望我的组件能够接受类型参数但也有复合组件。目前我有 const lambda fn 组件const Table = React.FC&lt;TableProps&gt; &amp; Row: React.ComponentType&lt;RowProps&gt; 并且我希望在使用这个组件时能够使用类型参数。【参考方案2】:

有一种模式可以缓解此问题,方法是在组件之外声明通用组件类型别名,然后在需要时简单地声明它。

没有那么漂亮,但仍然可重复使用且严格。

interface IMyComponentProps<T> 
  name: string
  type: T


// instead of inline with component assignment
type MyComponentI<T = any> = React.FC<IMyComponentProps<T>>

const MyComponent: MyComponentI = props => <p ...props>Hello</p>

const TypedComponent = MyComponent as MyComponentI<number>

【讨论】:

这可能不符合泛型的目的。开发人员可能需要重写每个组件的功能并且不能有共同的行为。 const MyComponent: MyComponentI = props =&gt; &lt;p ...props&gt;Hello&lt;/p&gt; 每一个组件都会重复这一行。【参考方案3】:

工厂模式:

import React,  SFC  from 'react';

export interface GridProps<T = unknown> 
  data: T[];
  renderItem: (props:  item: T ) => React.ReactChild;


export const GridFactory = <T extends any>(): SFC<GridProps<T>> => () => 
  return (
    <div>
      ...
    </div>
  );
;

const Grid = GridFactory<string>();

2021 年 8 月 3 日更新

为了避免钩子错误规则,您必须像这样巧妙地使用语法:

import React,  FC  from 'react';

export interface GridProps<T = unknown> 
  data: T[]
  renderItem: (props:  item: T ) => React.ReactChild


export const GridFactory = <T extends any>() => 
  const Instance: FC<GridProps<T>> = (props) => 
    const [state, setState] = useState(props.data)

    return <div>...</div>
  

  return Instance


const Grid = GridFactory<string>()

【讨论】:

&lt;T extends any&gt;是不是用来避免TS把它当作类型断言来对待?聪明的主意。 这是正确的。如果需要,它也可以在这里扩展另一种类型【参考方案4】:

我提出了一个类似但略有不同的解决方案(与朋友集思广益)。我们试图创建一个 Formik 包装器,并设法让它以下列方式工作:

import React,  memo  from 'react';

export type FormDefaultProps<T> = 
  initialValues: T;
  onSubmit<T>(values: T, actions: FormikActions<T>): void;
  validationSchema?: object;
;

// We extract React.PropsWithChildren from React.FunctionComponent or React.FC
function component<T>(props: React.PropsWithChildren<FormDefaultProps<T>>) 
  // Do whatever you want with the props.
  return(<div>props.children</div>


// the casting here is key. You can use as typeof component to 
// create the typing automatically with the generic included..
export const FormDefault = memo(component) as typeof component;

然后,您可以像这样使用它:

 <FormDefault<PlanningCreateValues>
        onSubmit=handleSubmit
        initialValues=PlanningCreateDefaultValues
      >
         /*Or any other child content in here */
        pages[page]
</FormDefault>

我无法通过方法表达式实现这一点:

const a: React.FC&lt;MyProp&gt; = (prop) =&gt; (&lt;&gt;MyComponent&lt;/&gt;);

【讨论】:

我走了你的路,onSubmit 中的values 参数总是未知的。你知道我哪里出错了吗?【参考方案5】:

@chris 在这里介绍的工厂模式很棒,但我不能使用 React Hooks。 所以我正在使用这个。

// Props
interface Props<T> 
  a: T;


// Component
export const MyComponent: <T>(p: PropsWithChildren<Props<T>>) => React.ReactElement = props => 
  return <div>Hello Typescript</div>;
;

如果您不需要孩子,您可以删除 PropsWithChildren 部分。 道具分解和钩子也可以。

export const MyComponent: <T>(p: Props<T>) => React.ReactElement = ( a ) => 
  const [myState, setMyState] = useState(false);
  return <div>Hello Typescript</div>;
;

【讨论】:

【参考方案6】:

根据 jmattheis 的帖子的通用无状态组件示例。

MyGenericStatelessComponent.tsx

import React from "react";

type Prop<T> = 
    example: T;
;

const MyGenericStatelessComponent: <T extends Record<string, number | string>>(props: Prop<T>) => JSX.Element = <
    T extends Record<string, unknown>
>(
    props: Prop<T>
): JSX.Element => 
    return (
        <div>
            Example Prop id: props.example.id, Example Prop name: props.example.name
        </div>
    );
;

export default MyGenericStatelessComponent;

用法:

<MyGenericStatelessComponent example= id: 1, name: "test01"  />

【讨论】:

您的示例只是一个返回元素的函数。此外,OP 用从 TS 2.9.1 开始的首选方式更新了他的问题【参考方案7】:

使用T = any 作为@vadistic 示例有效,但您不会进行任何类型检查。使用此代码,您将完成代码完成和类型检查。

interface IProps<TModel> extends RouteComponentProps 
    headerText?: string | React.ReactNode;
    collection: TModel[];


interface ICommonSortableType extends ISortableItem 
    id: number;
    isCorrectResponse: boolean;


interface ISortableItem 
    sortableId: number;
    

type GenericFunctionalComponent<TModel> = React.FC<IProps<TModel>>;
const CommonSortableList: GenericFunctionalComponent<ICommonSortableType> = (props) => 
...

然后可以这样使用:

class CommonSortableType 
    public sortableId: number = -1;
    public id: number = -1;
    public isCorrectResponse: boolean = false;


<CommonSortableList
    collection=item.commonSortableTypes //Is CommonSortableType[]
    headerText=<FormattedMessage id="item.list" />
</CommonSortableList>

class ExtendedOptionDto extends OptionDto implements ICommonSortableType 
    public sortableId: number = -1;


class OptionDto 
    public id: number = -1;
    public isCorrectResponse: boolean = false;


<CommonSortableList
    collection=item.extendedOptionDtos //Is ExtendedOptionDto[]
    headerText=<FormattedMessage id="item.list" />
</CommonSortableList>

【讨论】:

【参考方案8】:

我有办法,但我不确定是否完美

interface CategoryRelationProps<T> 
    text: T;


export const Component= <T,>(props: ComponentProps<T>) => 
  const  text  = props
  const [s] = useState(0) // you can use hook
  return (<div>yes</div>)


你可以像这样使用组件:

 (
  <>
    <Component<string> text="some text" />
  </>
 )

【讨论】:

通用类型(T)与打字稿中的任何类型有啥区别

】通用类型(T)与打字稿中的任何类型有啥区别【英文标题】:WhatarethedifferencebetweengenericType(T)vsanyintypescript通用类型(T)与打字稿中的任何类型有什么区别【发布时间】:2017-10-1619:26:59【问题描述】:打字稿中genericType(T)与any... 查看详情

无法访问父组件 React 打字稿中的转发 Ref 值

】无法访问父组件React打字稿中的转发Ref值【英文标题】:Can\'taccessforwarededRefvalueinparentcomponentReacttypescript【发布时间】:2021-09-2217:56:50【问题描述】:我有一种情况,我创建了一个输入组件。这是一个自定义组件,我想访问用... 查看详情

在打字稿中获取枚举键作为联合字符串的通用类型?

】在打字稿中获取枚举键作为联合字符串的通用类型?【英文标题】:Generictypetogetenumkeysasunionstringintypescript?【发布时间】:2018-05-1617:36:15【问题描述】:考虑以下打字稿枚举:enumMyEnumA,B,C;如果我想要另一种类型,即该枚举的键... 查看详情

打字稿中具有通用键的对象

】打字稿中具有通用键的对象【英文标题】:Objectwithgenerickeysintypescript【发布时间】:2020-04-2000:52:44【问题描述】:我想创建一个通用函数,它接受一个对象,然后进行一些转换并返回具有相同键和不同值的新对象。我正在尝试... 查看详情

如何处理打字稿中的状态?

】如何处理打字稿中的状态?【英文标题】:Howtohandlestatesintypescript?【发布时间】:2022-01-2113:48:41【问题描述】:您好,我是打字稿的新手,我有工作要做。我需要制作动态类,类似于下面的代码。importReact,ReactNode,useStatefrom"reac... 查看详情

React 无状态组件的 TypeScript 返回类型是啥?

】React无状态组件的TypeScript返回类型是啥?【英文标题】:WhatistheTypeScriptreturntypeofaReactstatelesscomponent?React无状态组件的TypeScript返回类型是什么?【发布时间】:2017-10-2307:47:30【问题描述】:这里的返回类型是什么?constFoo:()=>... 查看详情

React 复选框事件和处理程序的打字稿类型?

...Typescript中构建类似thisReactexample的东西。目标是让父级有状态,并创建几个无状态的子组件,将它们的点击传回父级。由于示例是用Javascript编写的,我不知道输入框事件和onChang 查看详情

带有打字稿的反应材料表显示通用类型错误

】带有打字稿的反应材料表显示通用类型错误【英文标题】:react-materialtablewithtypescriptshowsgenerictypeerror【发布时间】:2020-03-0423:02:30【问题描述】:我正在尝试在Typescript项目下运行react-material。由于我是Typescript的新手,我遇到... 查看详情

Typescript 无状态 HOC react-redux 注入道具打字

】Typescript无状态HOCreact-redux注入道具打字【英文标题】:TypescriptstatelessHOCreact-reduxinjectedpropstyping【发布时间】:2020-09-2112:06:36【问题描述】:我正在使用typescript,但我似乎无法弄清楚如何正确键入我的无状态组件,这些组件都... 查看详情

如何使用打字稿中的查找来推断类型化的 mapValues?

...Howtoinferatypedarrayfromadynamickeyarrayintypescript?我正在寻找一个通用对象,它接收任意键的映射以查找值,并返回具有类型值的相同键(如类型化_. 查看详情

避免任何类型在打字稿中获取枚举值

...7-0822:47:24【问题描述】:我需要遍历枚举类型以填充反应组件中的一些选项。在枚举下方找到从中返回键和值的函数。exportenumProyectTypetime,hits,value,resultsfunctionprojectTypeValues()constvalues 查看详情

如何在打字稿中“填写”通用参数

】如何在打字稿中“填写”通用参数【英文标题】:Howto"fillin"genericparameterintypescript【发布时间】:2021-05-2122:20:50【问题描述】:假设我有一个像这样的通用打字稿函数:functiondoThing<T>(param:T):T//...我有一个像这样的... 查看详情

获取泛型函数的类型而不调用打字稿中的函数

...布时间】:2019-05-2923:22:20【问题描述】:我有一个这样的通用函数:functionfoo<T>(val:T)returnval;我有一些类型:typeStringType=string;typeNumType=numbe 查看详情

如何为无状态 React 组件创建 TypeScript 类型定义?

】如何为无状态React组件创建TypeScript类型定义?【英文标题】:HowdoIcreateaTypeScripttypedefinitionforastatelessReactcomponent?【发布时间】:2018-11-2912:20:01【问题描述】:我正在尝试为现有的statelessReact组件套件创建类型定义,这样我就可... 查看详情

尝试在打字稿中使用 React useref 时出错

...【问题描述】:使用React和typescript我正在构建一个选项卡组件,您可以在其中通过溢出从左到右滚动选项卡链接:滚动集。这适用于触控板,但我需要为鼠标用户实现一种方法,以便他们可以像在此代码笔中一样单击和滚动:htt... 查看详情

如何将方法的泛型类型限制为打字稿中的对象?

】如何将方法的泛型类型限制为打字稿中的对象?【英文标题】:Howtorestrictagenerictypeofamethodtoanobjectintypescript?【发布时间】:2021-11-2503:15:32【问题描述】:我一直在尝试为我的方法提出一个泛型类型,并将该类型限制为具有以下... 查看详情

react中的componentpurecomponent无状态组件之间的比较

React中的Component、PureComponent、无状态组件之间的比较tableth:first-of-typewidth:150px组件类型说明React.createClass不使用ES6语法,只能使用React.createClass来创建组件;React对属性中的所有函数都进行了this绑定Component使用ES6语法创建组件;Rea... 查看详情

如何在打字稿中使用 react-navigation 的 withNavigation?

】如何在打字稿中使用react-navigation的withNavigation?【英文标题】:Howtousereact-navigation\'swithNavigationintypescript?【发布时间】:2019-01-0605:27:27【问题描述】:我正在尝试将react-native、react-navigation和typescript一起使用来创建一个应用程... 查看详情