具有'as'属性的通用React TypeScript组件(能够呈现任何有效的dom节点)

时间:2019-10-02 11:44:05

标签: javascript reactjs typescript typescript-generics

在下面的示例中,我按预期的那样工作了,我的问题是-是否仍然可以重写它,这样我就不必同时通过通用的SyncManagerT道具。理想情况下,我只想传递as prop并让组件的prop接口使用它。

在TypeScript中可以吗?

as

1 个答案:

答案 0 :(得分:0)

实现第二种变体非常容易,即需要显式类型参数的变体:

解决方案之一

import * as React from 'react';

type Props<K extends keyof JSX.IntrinsicElements> = JSX.IntrinsicElements[K];

declare class MyComponent<K extends keyof JSX.IntrinsicElements> extends React.Component<Props<K>> {}

<MyComponent<'a'> href="https://example.com/" id="myLink" />;

解决方案二

当涉及第一个变体时,则比较棘手。您想要的不是通用组件,而是道具的结合。为了说明原因,让我们考虑一个具体示例,其中MyComponent仅处理abutton的并集。

import * as React from 'react';

type Props =
   | ({ as: 'a' } & JSX.IntrinsicElements['a'])
   | ({ as: 'button' } & JSX.IntrinsicElements['button']);

declare class MyComponent<T extends 'a' | 'button'> extends React.Component<Props> {}

<MyComponent as="a" href="https://example.com" />; // ✔ OK
<MyComponent as="button" href="https://example.com" />; // ✘ Compile-time error

MyComponent不必泛泛即可识别其应接收的道具。 as道具是足够的判别。

我们可以通过创建所有标签及其相应道具的并集来概括该示例:

import * as React from 'react';

type Props = {
  [K in keyof JSX.IntrinsicElements]: { as: K } & JSX.IntrinsicElements[K];
}[keyof JSX.IntrinsicElements];

declare class MyComponent extends React.Component<Props> {}

<MyComponent as="a" href="https://example.com" />; // ✔ OK
<MyComponent as="button" href="https://example.com" />; // ✘ Compile-time error

这将完成工作,就像我们手动定义联合一样。但是,创建如此庞大的联盟存在弊端:

  • IntelliSense变得非常缓慢
  • 错误消息变得含糊不清
  • 总体复杂度增加。

需要注意的一点! ;)