簡體   English   中英

如何在TypeScript中鍵入“as”JSX屬性?

[英]How do I type this 'as' JSX attribute in TypeScript?

我正在描述一個React庫,它通過名為as的屬性獲取組件或HTML標記名稱。 當給定as屬性時,它會從該組件/標記名稱創建一個元素,並傳遞任何其他給定的屬性。

這里有些例子:

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

我知道Semantic 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>
}

讓我們回到我們提到的那兩種類型。 AnyTag是JSX標簽可以是的任何東西。

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!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM