有没有办法提取 JSX 元素的道具类型?

Posted

技术标签:

【中文标题】有没有办法提取 JSX 元素的道具类型?【英文标题】:Is there a way to extract the type of the props of a JSX Element? 【发布时间】:2021-06-19 13:28:33 【问题描述】:

我的意图是从给定的 JSX 元素中提取道具,这可能吗?

这几乎是我失败的尝试...... 在此先感谢您的帮助;)

function getComponentProps<T extends React.ReactElement>(element: T): ExtractProps<T>;

function Component( name :  name: string ) 
  return <h1>name</h1>;


type ExtractProps<TComponentOrTProps> = TComponentOrTProps extends React.ComponentType<infer TProps>
  ? TProps
  : TComponentOrTProps;

const componentProps = getComponentProps(<Component name="jon" />); //type is JSX.Element

【问题讨论】:

【参考方案1】:

在大多数情况下,你不能这样做。

理论中,React.ReactElement 类型是泛型的,类型参数P 取决于道具。所以如果你有一个强类型元素,那么你可以向后工作。

type ElementProps<T extends React.ReactNode> = T extends React.ReactElement<infer P> ? P : never;

现实中,只有通过 React.createElement 而不是 JSX 创建元素,才能获得正确的道具类型。

任何 JSX 元素 &lt;Component name="John" /&gt; 只会获得 JSX.Element 类型,它显然没有关于 props 的信息,所以你不能从它向后工作到 props 类型。

const e1 = React.createElement(
  Component,
   name: 'John' 
)

type P1 = ElementProps<typeof e1> // type: name: string

console.log(getElementProps(e1)); // will log name: "John"
const e2 = <Component name="John" />

type P2 = ElementProps<typeof e2>  // type: any

console.log(getElementProps(e2)); // will log name: "John"

Playground Link

从不同的角度处理这种情况要容易得多。如果您的函数采用 Componentdiv 之类的组件而不是已解析的元素,则您将能够派生正确的道具类型。您可以将ComponentProps 实用程序类型用于函数和类组件,将JSX.IntrinsicElements 映射用于内置组件。

【讨论】:

老实说,这很有帮助。再次感谢您的帮助和知识分享;)【参考方案2】:

您可以使用任何组件提取道具的类型

React.ComponentProps<typeof T>

您可以参考此TS Playground 了解更多选项

import * as React from 'react';

type TProps = 
   name:string;
   age:number;
   is***:boolean;
 

const App = (props:TProps) => <div>Hello World</div>;

//You can extract any components props like this.
type AppProps = React.ComponentProps<typeof App>;

`

【讨论】:

【参考方案3】:

这对于getComponentProps(&lt;Component name="jon" /&gt;); 是不可能的,因为写出的 JSX-Elements 总是导致 JSX.Element-type 没有提供任何您可以提取的额外类型信息。如果你从组件函数本身中提取它是可能的:

export function Component( name :  name: string) 
    return <h1>name</h1>;


function getComponentProps<T extends (...args: any[]) => JSX.Element>(element: T): Parameters<T>[0] 
    return null as any;


const test = getComponentProps(Component); //  name: string;

此解决方案使用实用程序类型parameter,它从函数中推断出所有参数。然后我们索引第一个参数,因为 prop 对象是纯 jsx 函数的第一个参数。不过,类组件需要不同的解决方案。

【讨论】:

嗯...是的,不幸的是,我正在尝试的内容当时无法实现。因为我想获取一个 JSX 元素(可能已经带有一些道具),然后返回它的克隆,它采用相同类型的道具......无论如何,非常感谢你的帮助;) @PedroFigueiredo 您需要知道哪些道具已经通过的实际用例是什么?您可能想要对React.childrencloneElement 进行一些操作。 是这样的,我将一个组件用它已经使用的相同道具克隆它:cutt.ly/XxxZEYe 所以你可以获取一个组件并返回一个组件——即just an HOC,我已经输入了一百万次:) 你可以获取一个元素并返回一个元素like this。获取一个元素并返回一个组件是您可以做的事情,但这有点奇怪,而且您将很难获得良好的类型支持。 How about this? 将部分道具分配给内部 JSX 元素。

以上是关于有没有办法提取 JSX 元素的道具类型?的主要内容,如果未能解决你的问题,请参考以下文章

JSX 元素类不支持属性,因为它没有“道具”property.ts(2607)

jsx 中的元素道具

TypeScript、react-router 和 jsx:JSX 元素类型 'Route' 没有任何构造或调用签名

JSX 元素类型 'Route' 没有任何构造或调用签名

JSX 元素类型“...”没有任何构造或调用签名

TypeScript 3:JSX 元素类型“组件”没有任何构造或调用签名。 [2604]