用于从字符串创建 JSX 元素的正确 TypeScript 类型

cal*_*wan 14 javascript typescript reactjs

我有一个组件,我想默认将其呈现为h2. 如果他们愿意,我希望消费者能够指定不同的元素。下面的代码导致错误:

TS2604 - JSX element type 'ElementType' does not have any construct or call signatures

我想我明白为什么它会失败,TS 期望渲染一个 React 节点。为清楚起见,只要变量以大写字母开头(这是 JSX 要求),React能够呈现作为字符串引用的元素。我之前在 vanilla JS + React 中成功做到了这一点,我只是不知道如何满足 TypeScript。

我怎样才能让 TypeScript 在不诉诸于的情况下呈现这个 elementType?: any

import React, {ReactNode} from 'react'

interface Props {
    children: ReactNode;
    elementType?: string;
}

export default function ({children, elementType: ElementType = 'h2'}: Props): JSX.Element {
    return (
        <ElementType>{children}</ElementType>
    );
}
Run Code Online (Sandbox Code Playgroud)

小智 6

首先,介绍一下 JSX。它只是一个语法糖 for React.createElement,它是一个 JavaScript 表达式。

考虑到这些知识,现在让我们来看看为什么 TypeScript 会抱怨。您定义elementTypestring,但是,当您实际使用它时,它变成了一个 JavaScript 表达式。string当然类型没有任何构造或调用签名。

现在我们知道了根本原因。在 React 中,有一种类型叫做FunctionComponent. 可以猜到,它是一个函数表达式,这正是我们想要的。所以你可以定义elementTypestring | FunctionComponent. 这应该让 TypeScript 开心 :)

仅供参考:定义道具类型的推荐方法是这样做:

const MyComponent: FunctionComponent<Props> = (props) => {}
Run Code Online (Sandbox Code Playgroud)


Kar*_*ski 5

使用keyof JSX.IntrinsicElements

import * as React from 'react'

interface Props {
  children: React.ReactNode;
  elementType?: keyof JSX.IntrinsicElements;
}

export default function ({ children, elementType: ElementType = 'h2' }: Props): JSX.Element {
  return (
    <ElementType>{children}</ElementType>
  );
}
Run Code Online (Sandbox Code Playgroud)


小智 5

我正在制作一个<Text>组件,并希望缩小开发人员可以传入的可能 HTML 标签集,使其仅包含“基于文本”的元素span,例如ph1、 等。

所以我有类似的东西:


// Narrow the tags to p, span, h1, etc
type AS = Extract<keyof JSX.IntrinsicElements, 'p' | 'span' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5'>;

interface Props {
  children: React.ReactNode;
  as: AS;
  // ... other props here
}

export function Text(props: Props) {  

  // Render the text with the appropriate HTML tag.
  return (
    <HTMLTag as={props.as}>
      {props.children}
    </HTMLTag>
  );
}

interface HTMLTagProps extends HTMLAttributes<HTMLOrSVGElement> {
  as: AS;
}

function HTMLTag({ as: As, ...otherProps }: HTMLTagProps) {
  return <As {...otherProps} />;
}
Run Code Online (Sandbox Code Playgroud)