通用打字稿组件继承组件道具
Posted
技术标签:
【中文标题】通用打字稿组件继承组件道具【英文标题】:Generic typescript component inherit component props 【发布时间】:2019-05-22 16:05:07 【问题描述】:我正在使用 Typescript,我想对通用组件进行 prop 验证。我想创建一个 Field 组件,它呈现标签、错误消息和作为道具传递的组件。我进行了多次尝试以使其工作,但其中一部分或另一部分都失败了。我也阅读了数十篇文章,但找不到任何人面临完全相同的问题。
这是我目前得到的:
interface IFieldProps<P>
is: React.ComponentType<P>;
class Field<P> extends React.PureComponent<IFieldProps<P>>
render()
const is, ...rest = this.props;
const Component = is;
return (
<div>
<Component ...rest />
</div>
);
interface ITextInputProps
value: string
class TextInput extends React.PureComponent<ITextInputProps>
render()
return (
<input ...this.props />
);
const render = () => <Field is=TextInput />;
打字稿编译器并没有大喊 value
方法中缺少 value
属性,所以我将使 IFieldProps
从 P
扩展,这应该可以工作:
interface IFieldProps<P> extends P
is: React.ComponentType<P>;
编译器现在说“一个接口只能扩展一个类或另一个接口”。 好的,那我就把它变成一个类型,不用担心:
type IFieldProps<P> = P &
is: React.ComponentType<P>;
现在一切都搞砸了。它在...rest
上大喊“Rest 类型只能从对象类型创建”。它在<Component />
上大喊“JSX 元素类型'组件'没有任何构造或调用签名”。最后它在<Field />
上大喊value
道具丢失了——与此同时,道具上的自动完成功能在 vscode 中停止工作。
我想如果我对 P 有一些限制(例如P extends
),可以解决一些问题,但它没有。
如何制作一个通用组件来继承作为道具传递的组件的道具?还是有些过于复杂?其他人如何解决这个问题?
【问题讨论】:
【参考方案1】:当包装的组件道具保存在另一个道具中时它可以工作(而不是与is
混合):
interface IFieldProps<P>
is: React.ComponentType<P>;
props: P;
;
class Field<P> extends React.PureComponent<IFieldProps<P>>
render()
const is, props = this.props;
const Component = is;
return (
<div>
<Component ...props />
</div>
);
interface ITextInputProps
readonly value: string;
class TextInput extends React.PureComponent<ITextInputProps>
render()
return (
<input ...this.props />
);
const render = () => <Field is=TextInput props= value: '' />;
我无法根据消息找到错误的来源:
键入“选择 & 只读>,“儿童” |排除>' 不是 可分配给类型 'IntrinsicAttributes & LibraryManagedAttributes["is"], P & children?: 反应节点; >'。输入'选择& 只读>,“儿童” |排除>' 不是 可分配给类型 'LibraryManagedAttributes["is"], P & 孩子?:反应节点; >'。
【讨论】:
我也想过这个解决方案,但是我觉得我必须修改组件的 API 只是因为我使用的是 Typescript。我还担心这会迫使 PureComponents 重新渲染,因为props
会在每次渲染中发生变化。我想在不修改 API 的情况下将这种模式用于我的按钮/链接以及 <Button onClick=this.doThat>Submit</Button>
和 <Button is=Link to="/somewhere">Redirect me</Button>
。
我同意。但是,我感觉这更多地与 React 类型定义有关,而不是 TypeScript 本身。当我试图在不更改所需 API 的情况下使其工作时,帮助的是在调用端使用类型参数 (const render = () => <Field<ITextInputProps> is=TextInput value="foo" />
) — 但包装组件的类型 (is
) 仍然推断不正确。跨度>
以上是关于通用打字稿组件继承组件道具的主要内容,如果未能解决你的问题,请参考以下文章