【问题标题】:Passing props in React jsx as generics将 React jsx 中的 props 作为泛型传递
【发布时间】:2022-01-17 16:40:27
【问题描述】:

在我的 react 应用程序中,我想将特定接口作为泛型传递给非特定组件。

例如我有三个特定的接口

SpecificInterfaces.jsx
export interface InterfaceA {
   name: string
   age: number
   ...
}

export interface InterfaceB {
    name: string
    movies: string[]
    count: number
    ...
}

export interface InterfaceC {
    name: string
    somestuff: someType
}

对于每个接口,我都有一个特定的组件 ComponentA、ComponentB 和 ComponentC。 这些组件需要在共享组件ComponentShared中使用。

现在,例如,我希望在我的 ComponentA 中返回 SharedComponent,其具有 InterfaceA 的通用类型和 InterfaceA 类型的道具,如下所示:

ComponentA.jsx
export interface Props<T> {
    importData: T[]
    ... some props... 
}

const props: Props<InterfaceA> = {
importData: importData //This is from Interface Type InterfaceA
... someProps ...
}
  return (
        <React.Fragment>
            <SharedComponent<InterfaceA> {...props} />
        </React.Fragment>
    )

在我的 sharedComponent 中,我想像这样访问特定传递的泛型类型:

SharedComponent.jsx
const SharedComponent= <T,>({
   importData,
   ...the passed Props
}: Props<T>): JSX.Element => {
importData.map((data: T) =>
    data.name) 

importData.map((data:T) =&gt; data.name) 它会抛出一个错误,说 T 没有 name 的成员。所以我想我在这里传入的泛型不能正常工作,因为作为泛型传入的 InterfaceA 具有成员“名称”,就像任何其他 InterfaceB 和 InterfaceC 一样。我做错了什么?

【问题讨论】:

    标签: javascript reactjs typescript generics jsx


    【解决方案1】:

    TypeScript 对函数内部的泛型一无所知,除非您通知它。您需要从具有您在函数内部使用的属性的类型扩展您的通用 T。考虑这个例子:

    TS Playground

    function logNamesBroken <T>(objects: T[]): void {
      for (const obj of objects) {
        console.log(obj.name);
    /*                  ^^^^
    Property 'name' does not exist on type 'T'.(2339) */
      }
    }
    
    type BaseObject = {
      name: string;
    };
    
    function logNames <T extends BaseObject>(objects: T[]): void {
      for (const obj of objects) {
        console.log(obj.name); // ok now
      }
    }
    

    更多,根据您问题中的代码:

    TS Playground

    import {default as React} from 'react';
    
    interface BaseItem {
      name: string;
    }
    
    interface InterfaceA extends BaseItem {
      age: number;
    }
    
    interface Props<T extends BaseItem> {
      importData: T[];
    }
    
    const SharedComponent = <T extends BaseItem>({
      importData,
    }: Props<T>): React.ReactElement => {
      return (
        <ul>
          {
            importData.map((data, index) => (
              <li key={`${index}-${data.name}`}>{data.name}</li>
            ))
          }
        </ul>
      );
    };
    
    const importData: InterfaceA[] = [{name: 'a', age: 1}, {name: 'b', age: 2}];
    
    const props: Props<InterfaceA> = {
      importData,
    };
    
    const AnotherComponent = (): React.ReactElement => (
      <React.Fragment>
        <SharedComponent {...props} />
      </React.Fragment>
    );
    

    【讨论】:

    • 感谢您的快速回复!我是否理解正确,那么我想要实现的目标根本不可能?因为我有几个接口或者类型,应该和SharedComponent兼容。这些接口或类型也将在不久的将来扩展和/或由新类型补充......
    • @Alex 老实说,我很难理解您问题中的代码,因为它不是有效的语法:有未注释的 cmets 与代码混合,return 函数外的语句等. 我很难弄清楚您的真正意图是什么,但是,我根据收集到的信息用另一个示例更新了我的答案。
    • 您的新解决方案似乎符合我的要求!我需要验证一下,但到目前为止它看起来很棒。太感谢了!是的,我知道,老实说,我不确定我应该做什么,我刚刚得到了“使组件与泛型一起工作”的任务......:D
    猜你喜欢
    • 2020-02-15
    • 2019-06-04
    • 1970-01-01
    • 2019-09-11
    • 2019-08-11
    • 2023-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多