我有一个HOC,它为包装的组件提供一个属性。
我想编写Typescript类型定义,以正确公开此HOC创建的组件的Props类型:基本上复制(推断)包装组件的props类型,并删除我的HOC提供的属性。有可能吗?
在下面的示例中,我有一个HOC withBar
,它为接受该包装的任何组件提供了bar:string
道具。因此,Foo = withBar(FooBar)
组件应具有FooBarProps
除外的道具bar
,这意味着仅{foo: string}
。但是Typescript显然仍然认为Foo
组件也应该具有foo
属性。
我使用打字稿3.3.1
import * as React from "react";
interface FooBarProps {
foo: string;
bar: string;
}
class FooBar extends React.PureComponent<FooBarProps> {
public render() {
return <>{this.props.foo} {this.props.bar}</>;
}
}
export function withBar<TProps>(
WrappedComponent: React.ComponentType<TProps & {bar: string}>
) {
return class WithBar extends React.PureComponent<TProps> {
public render() {
return <WrappedComponent
{...this.props}
bar={"BAR"}
/>;
}
};
}
const Foo = withBar(FooBar);
// Typescript complains here:
// Error:(29, 14) TS2741: Property 'bar' is missing in type
// '{ foo: string; }' but required in type 'Readonly<FooBarProps>'.
const foo = <Foo foo="FOO" />;
答案 0 :(得分:1)
关于以下内容,它可以工作,但可能无法完全回答您的问题。 https://codesandbox.io/embed/peaceful-star-194g5?fontsize=14
其要点是将Foo和Bar分成不同的类型,并将它们结合在一起以组成包装组件。如果您不想访问沙盒,请使用以下代码:
import * as React from "react";
interface BarProps {
bar: string;
}
interface FooProps {
foo: string;
}
type FooBarProps = FooProps & BarProps;
class FooBar extends React.PureComponent<FooBarProps> {
public render() {
return (
<>
{this.props.foo} {this.props.bar}
</>
);
}
}
export function withBar<TProps>(
WrappedComponent: React.ComponentType<TProps & BarProps>
) {
return class WithBar extends React.PureComponent<TProps> {
public render() {
return <WrappedComponent {...this.props} bar={"BAR"} />;
}
};
}
const Foo = withBar(FooBar);
// Typescript complains here:
// Error:(29, 14) TS2741: Property 'bar' is missing in type
// '{ foo: string; }' but required in type 'Readonly<FooBarProps>'.
export const Foof = () => <Foo foo="FOO" />;
答案 1 :(得分:0)
Pick
和Exclude
类型可以在这里提供帮助:
interface Foo{
woo: string
doo: number
}
interface Goo{
doo: number
}
type FooExcludeGoo = Pick<Foo, Exclude<keyof Foo, keyof Goo>> // {woo:string}
答案 2 :(得分:0)
我终于找到的最佳解决方案:
export function withBar<TProps extends {bar: string}>(
WrappedComponent: React.ComponentType<TProps>
) {
return class WithBar extends React.PureComponent<
Pick<TProps, Exclude<keyof TProps, "bar">> // = Omit<TProps, "bar">
> {
public render() {
return <WrappedComponent
{...this.props as any /* still can't do better than using any here */}
bar={"BAR"}
/>;
}
};
}
这个想法是,通用参数TProps
包含我要从结果组件中排除的属性,并在结果组件的类型签名中手动排除它们。
唯一的警告是Typescript无法确定传递给包装组件的{...this.props}
是否具有正确的类型,因此我不得不使用any
,但幸运的是,它仅影响组件的内部结构,并且所有暴露在外面的类型都应该准确。
那里的Typescript错误消息也非常流行,因此我无法调试原因:TS2322: Type 'Readonly<{ children?: ReactNode; }> & Readonly<Pick<TProps, Exclude<keyof TProps, "bar">>> & { bar: string; }' is not assignable to type 'IntrinsicAttributes & TProps & { children?: ReactNode; }'.
Type 'Readonly<{ children?: ReactNode; }> & Readonly<Pick<TProps, Exclude<keyof TProps, "bar">>> & { bar: string; }' is not assignable to type 'TProps'.