【问题标题】:Typings for redux / connect like decoratorredux 的类型 / 像装饰器一样连接
【发布时间】:2018-12-05 02:25:26
【问题描述】:

我正在尝试创建一个装饰器,其行为类似于 redux 的 connect 装饰器:在装饰组件中注入一些额外的道具。我的打字有问题

extra.d.ts

export interface ExtraProps {
  extra: string;
}

// problem must be with this. Intent is to "add" the "extra" prop
// and not require it when the user actually renders it.
export function extra<P>(): (
  Comp: ComponentType<P & ExtraProps>
) => ComponentType<P>;

sample.tsx

interface MyCompProps extends ExtraProps {
  notSoExtra: string;
}

class MyComp extends React.Component<MyCompProps> {
  render() {
    console.log(this.props.extra, this.props.notSoExtra); // ok
    return null;
  }
}

// Decorating it here, prop types should be { notSoExtra: string } 
const MyCompWithExtra = extra()(MyComp);

class App extends React.Component {
  render() {
    return <MyCompWithExtra notSoExtra="boring prop" />;
    // error ^^^^^^
  }
}

所以在渲染 MyCompWithExtra 时出现错误:

[ts] 类型 '{ notSoExtra: string; }' 没有共同的属性 类型'IntrinsicAttributes&{孩子?:ReactNode; }'。

当我像这样明确指定道具类型时:

const MyCompWithExtra = extra<MyCompProps>()(MyComp);

渲染时出现不同的错误

[ts] 类型 '{ notSoExtra: string; }' 不可分配给类型 'IntrinsicAttributes & MyCompProps & { children?: ReactNode; }'。
键入'{ notSoExtra:字符串; }' 不可分配给类型 '我的CompProps'。 '{ notSoExtra: string; 类型中缺少属性 'extra' }'。

如何以某种方式键入装饰器,以便在渲染装饰组件时可以省略道具?

【问题讨论】:

    标签: reactjs typescript generics


    【解决方案1】:

    第一个问题是,如果你在extra函数中指定P参数,而需要推断它的信息将在返回的函数调用中指定,编译器将无法推断@ 987654323@。

    您可以使用单个函数,或者,如果您想指定其他参数,您可以从 extra 返回一个泛型函数。

    但更大的问题是P &amp; ExtraProps 并不意味着ExtraProps 中的属性不会包含在P 中。 P 将包含所有属性,&amp; ExtraProps 更多地作为对这些属性类型的约束。

    要创建一个从其他类型中排除属性的类型,您可以使用Pick 的组合从一个类型中选择特定属性,并使用Exclude&lt;keyof A, keyof B&gt;A 的键中排除B 的键。

    export interface ExtraProps {
        extra: string;
    }
    export function extra<P extends ExtraProps>(
        Comp: ComponentType<P>
    ) : ComponentType<Pick<P, Exclude<keyof P, keyof ExtraProps>>> {
        return null as any;
    }
    
    //Usage
    interface MyCompProps extends ExtraProps {
        notSoExtra: string;
    }
    
    class MyComp extends React.Component<MyCompProps> {
        render() {
            console.log(this.props.extra, this.props.notSoExtra); // ok
            return null;
        }
    }
    const MyCompWithExtra = extra(MyComp);
    let s = <MyCompWithExtra notSoExtra="boring prop" />;
    

    注意如果你想让用户有选择地指定extra,你可以返回ComponentType&lt;Pick&lt;P, Exclude&lt;keyof P, keyof ExtraProps&gt;&gt;&gt; &amp; Partial&lt;ExtraProps&gt;

    【讨论】:

      猜你喜欢
      • 2019-03-07
      • 2018-05-30
      • 2014-04-08
      • 2021-04-19
      • 2022-01-15
      • 1970-01-01
      • 2020-06-20
      • 2017-02-14
      • 2012-02-29
      相关资源
      最近更新 更多