当前位置: 首页 > 面试题库 >

如何在TypeScript中键入“ as” JSX属性?

松景铄
2023-03-14
问题内容

我正在描述一个React库,该库通过一个名为的属性采用一个组件或HTML标签名称as。给定as属性后,它将根据该组件/标签名称创建一个元素,并传递所有其他给定属性。

这里有些例子:

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

我知道语义UI在扩充方面做了类似的事情。我将如何在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!


 类似资料:
  • 问题内容: 强制转换为文件时,编译器将其假定为JSX,例如: 给出一个错误 JSX元素类型’HtmlInputElement’不是JSX元素的构造函数 如何将TypeScript转换为文件? 问题答案: 该运算符被引入TypeScript 1.6,以替换文件中的强制类型转换,例如: TypeScript Wiki解释了1.6的更改: 它使新运算符成为默认的转换方式(消除了JSX表达式与TypeSc

  • 我在TypeScript中有一个接口或抽象类,我有一大堆实现/扩展接口/类的类,我想用所有子类的构造函数生成一个数组,但我想把数组类型为接口/超类。这可能吗? 可以将键入以外的任何内容吗?我想尽可能地说得具体些。我知道在ActionScript中您至少可以执行,在Haxe中您可以执行,但是在TypeScript中您甚至不能作为afaik键入。

  • 问题内容: 我的问题很简单,我有一个以下JSON Typescript对象,并且我想迭代遍历JSON属性 使用的代码是以下有角TypeScript组件: 我真正需要的是遍历JSON的键值属性,并在我的HTML中显示它们。 非常感谢! 问题答案: 如果您使用的是Angular 6.1,请使用键值管道 对于Angular 5 示例:https://stackblitz.com/edit/keyvalu

  • 问题内容: 背后有不同的原因,但是我想知道如何简单地向JSX中的元素添加自定义属性? 问题答案: 编辑:更新以反映React 16 React 16本机支持自定义属性。这意味着向元素添加自定义属性现在就像将其添加至函数一样简单,如下所示: 先前的答案(第15和更早版本) 当前不支持自定义属性。有关更多信息,请参见此未解决的问题: 解决方法是,您可以在中执行以下操作:

  • React/Typescript中对象的类型是什么,例如: 如果我需要将它定义为一个对象,我应该输入什么类型,而不是

  • 在TypeScript中,< code>class关键字引入了值和类型: 有没有一种方法可以使函数返回既是类型又是值的东西? 问这个问题的另一种方法是:有没有办法在下面声明的类型,以便类型检查? 看到这个打字游戏了吗