如何在 TypeScript 中输入这个“as”JSX 属性?

2024-05-27

我正在描述一个 React 库,它通过名为的属性获取组件或 HTML 标签名称as。当给出as属性,它根据该组件/标签名称创建一个元素,并传递任何其他给定的属性。

这里有些例子:

<Foo as="a" href="https://example.com" />
<Foo as={FancyButton} fancyButtonAttr="hello!" />

我知道语义 UI 的作用与增强类似 https://react.semantic-ui.com/#augmentation。我该如何在 TypeScript 中输入这个内容?


我将举例说明此处给出的最基本的要求。您可以尝试泛化到做更复杂的事情。

首先,这是我们的神奇组件!

import * as React from "react";

function Foo<Tag extends AnyTag>(props: { as: Tag } & PropsOf<Tag>): JSX.Element;

注意两件事:

  • 一种类型称为AnyTag
  • 称为的实用程序类型PropsOf

那是我们的公开签名。我们也许能够使用该签名以类型安全的方式实现这一点,但我们可以在实现签名中进行一些“欺骗”。这取决于您作为实施者。

function Foo(props: any) {
    return <div>Implementation goes here!</div>
}

让我们回到我们提到的这两种类型。AnyTagJSX 标签可以是任何东西。

type AnyTag = string
            | React.FunctionComponent<never>
            | (new (props: never) => React.Component);

PropsOf尝试获取给定 HTML 标记名称或组件的预期属性。

type PropsOf<Tag> =
    Tag extends keyof JSX.IntrinsicElements ? JSX.IntrinsicElements[Tag] :
    Tag extends React.ComponentType<infer Props> ? Props & JSX.IntrinsicAttributes :
    never
;

现在让我们定义一些采用相同属性的组件 - 一个函数和一个类。

interface SomeProps {
  x: boolean; y: boolean; z: boolean;
}

function Bar(props: SomeProps) {
    return <div>{props.x} {props.y} {props.z}</div>;
}

class Baz extends React.Component<SomeProps> {
    render() {
        const { x, y, z } = this.props;
        return <div>{x} {y} {z}</div>;
    }
}

现在这是一些用法!

let a1 = <Foo as="a" href="https://kthxb.ai" />;         // good!
let a2 = <Foo as="div" href="https://kthxb.ai" />;       // error!
let a3 = <Foo as="a" href={100} />;                      // error!

let b1 = <Foo as={Bar} x y z />;                         // good!
let b2 = <Foo as={Bar} x y z asdsadsada />;              // error!
let b3 = <Foo as={Bar} x={1} y={2} z={3} asdsadsada />;  // error!

let c1 = <Foo as={Baz} x y z />;                         // good!
let c2 = <Foo as={Baz} x y z asdsadsada />;              // error!
let c3 = <Foo as={Baz} x={1} y={2} z={3} asdsadsada />;  // error!

import * as React from "react";

// Here's our magic component!
// Note two things:
//   - A type called AnyTag
//   - A utility type called PropsOf
function Foo<Tag extends AnyTag>(props: { as: Tag } & PropsOf<Tag>): JSX.Element;

// That was our public signature. We might be able to implement this in a type-safe way using that signature,
// but we can "cheat" a little here in the implementation signature. This is up to you as the implementer.
function Foo(props: any) {
    return <div>Implementation goes here!</div>
}

// AnyTag is anything that a JSX tag can be.
type AnyTag = string
            | React.FunctionComponent<never>
            | (new (props: never) => React.Component);

// PropsOf tries to get the expected properties for a given HTML tag name or component.
type PropsOf<Tag> =
    Tag extends keyof JSX.IntrinsicElements ? JSX.IntrinsicElements[Tag] :
    Tag extends React.ComponentType<infer Props> ? Props & JSX.IntrinsicAttributes :
    never
;

// Let's now define a few components taking the same props - one function and one class.

interface SomeProps {
  x: boolean; y: boolean; z: boolean;
}

function Bar(props: SomeProps) {
    return <div>{props.x} {props.y} {props.z}</div>;
}

class Baz extends React.Component<SomeProps> {
    render() {
        const { x, y, z } = this.props;
        return <div>{x} {y} {z}</div>;
    }
}

// Now here's some usage!

let a1 = <Foo as="a" href="https://kthxb.ai" />;         // good!
let a2 = <Foo as="div" href="https://kthxb.ai" />;       // error!
let a3 = <Foo as="a" href={100} />;                      // error!

let b1 = <Foo as={Bar} x y z />;                         // good!
let b2 = <Foo as={Bar} x y z asdsadsada />;              // error!
let b3 = <Foo as={Bar} x={1} y={2} z={3} asdsadsada />;  // error!

let c1 = <Foo as={Baz} x y z />;                         // good!
let c2 = <Foo as={Baz} x y z asdsadsada />;              // error!
let c3 = <Foo as={Baz} x={1} y={2} z={3} asdsadsada />;  // error!
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 TypeScript 中输入这个“as”JSX 属性? 的相关文章

随机推荐

  • 未向 HAL 提供足够的数据,预期位置

    我在 Android Studio 中收到此错误 我只想在按下按钮时打印文本 我收到以下错误 每次按下按钮时都会出现该错误 如果我取消注释掉意图 它也可以正常工作 但是我拥有的代码越多 错误更改就越多 我实际上不确定这是真正的错误 我这么说
  • 单击“提交”按钮时 jQuery Stop .blur() 事件

    我正在使用简单的演示电子邮件注册表单构建一个小型登陆页面 我想让表单字段在聚焦时打开 然后在模糊时缩小 然而 我面临的问题是 当您单击提交按钮时 这会引发模糊功能 隐藏按钮并缩小表单 我需要找到一种方法 仅当用户单击专注于提交按钮时停止 b
  • 图例中标签的悬停样式

    如何设置图例中标签的悬停样式 如果可以设置的话cursor default在此示例中 将鼠标悬停在 东京 纽约 柏林 伦敦 标签上http www highcharts com demo http www highcharts com de
  • 如何运行 Windows 批处理文件但隐藏命令窗口?

    如何运行 Windows 批处理文件但隐藏命令窗口 我不希望 cmd exe 在执行文件时在屏幕上可见 这可能吗 如果你写一个非托管程序并使用创建进程 https learn microsoft com en us windows win3
  • RecyclerView 滚动不适用于 NestedScrollView

    我有一个布局 其中有一个 NestedScrollView 其中包含一个图像 多个按钮和一个 RecycleView 当我说recyclerView smoothScrollToPosition or recyclerView scroll
  • 如何在 Flask/SQLAlchemy 中 select_lated() ?

    有以下型号 class Question db Model id db Column db Integer primary key True title db Column db String 125 text db Column db T
  • 防止表单提交时出现默认 jQuery

    这有什么问题吗 HTML
  • 显示模板中存储为二进制 blob 的图像

    我有一个模型 其中图像存储为二进制 blob 我想在模板中显示该图像以及有关该对象的其他数据 由于图像不是一个单独的文件 我不知道如何显示它 我尝试过设置标题 或使用send file or render template 但我要么没有得到
  • 如何使用FeatureUnion转换PipeLine中的多个特征?

    我有一个 pandas 数据框 其中包含有关用户发送的消息的信息 对于我的模型 我感兴趣的是预测消息的缺失收件人 即给定消息的收件人 A B C 我想预测还有谁应该成为收件人的一部分 我正在使用 OneVsRestClassifier 和
  • 从多个文件加载 Flask 配置

    我需要从多个文件加载配置 我使用下面的代码来加载一个文件 我应该反复使用它吗 如何加载多个配置 app Flask name app config from object yourapplication default settings 您
  • 收到 404 时模型的 EmberJS 路由

    同样的文本也在 EmberJS 讨论区中开放 我有以下路线 App IndexCrmPersonEditRoute Ember Route extend model function params var person this store
  • 如何使用 CSS 使表格中的分隔线/边框消失?

    我有一个简单的 HTML 表格 我希望分隔线 边框 消失 所需的最终结果是一个除了实际文本之外不可见的表格 我尝试将 border 属性设置为 0 但没有帮助 我应该使用什么正确的 CSS 属性 table tr td th border
  • 对 .NET Windows 安装程序应用程序执行注册表搜索

    我有一个 NET winform 安装程序应用程序 在安装之前 我会进行注册表搜索以检查计算机上是否安装了 MS Access Runtime 搜索目标机器 搜索目标机器的属性 启动条件 启动条件的属性 但是我想避免对路径进行硬编码 例如
  • SWIG 类型映射 uint8_t* 从 C/C++ 到 java.nio.ByteBuffer

    我正在尝试将输入和输出缓冲区从 C 传递给 java 类 出于效率原因 我需要使用 ByteBuffer 这两个缓冲区都是在 C 部分中分配的 我需要将它们传递给一个 java 函数 该函数将使用输入缓冲区进行一些计算并将结果写入输出缓冲区
  • Fabric sudo 无密码解决方案

    这个问题是关于最佳实践的 我正在使用 Fabric 运行部署脚本 我的部署用户 deploy 需要 sudo 来重新启动服务 因此 我使用 Fabric 中的 sudo 函数在脚本中运行这些命令 这工作正常 但在脚本执行期间提示输入密码 我
  • MotionLayout:如何限制特定视图上的“OnSwipe”事件而不是整个屏幕上的“OnSwipe”事件

    我有一个带有以下 layoutDescription 场景文件 的运动布局
  • 如何在 xquery 中格式化小数?

    我正在尝试在 XQuery 中格式化小数 小数点是货币 所以格式应该是 例如 5573652 23应该5 573 652 23 and 352769应该352 769 or 352 769 00如果它更容易 更干净 现在我正在使用这个功能h
  • Angular2 - 自定义 CSS / JS 文件的文件夹是什么? [复制]

    这个问题在这里已经有答案了 我必须在我的 angular2 应用程序中包含一组 CSS 和 JS 文件 为了将它们包含在内 正确的文件夹是什么当我进行构建时 我应该把它们放进去吗SRC 资产或以下SRC 我的文件夹 定义后 我如何将它们包含
  • 如何在php中用一行调用两个方法?

    我在 Laravel 中看到在单行中调用多个方法 例如 DB get test gt toJson 我在该类中有一个很酷的类和视图方法 this gt call gt view welcome gt anotherMethod 我还想调用另
  • 如何在 TypeScript 中输入这个“as”JSX 属性?

    我正在描述一个 React 库 它通过名为的属性获取组件或 HTML 标签名称as 当给出as属性 它根据该组件 标签名称创建一个元素 并传递任何其他给定的属性 这里有些例子