代码之家  ›  专栏  ›  技术社区  ›  J. Hesters

TypeScript返回类型与decorator兼容

  •  2
  • J. Hesters  · 技术社区  · 7 年前

    我正在将React Native与TypeScript一起使用。我写了一个HOC,我喜欢用它作为装饰器,给组件一个徽章:

    import React, { Component, ComponentClass, ReactNode } from "react";
    import { Badge, BadgeProps } from "../Badge";
    
    function withBadge<P>(
      value: number,
      hidden: boolean = value === 0
    ): (WrappedComponent: ComponentClass<P>) => ReactNode {
      return (WrappedComponent: ComponentClass<P>) =>
        class BadgedComponent extends Component<P> {
          render() {
            return (
              <React.Fragment>
                <WrappedComponent {...this.props} />
                {!hidden && <Badge value={value} />}
              </React.Fragment>
            );
          }
        };
    }
    
    export default withBadge;
    

    现在的问题是,当我尝试使用此组件作为装饰器时,如下所示:

    import React, { PureComponent } from "react";
    import { Icon } from "react-native-elements";
    import { getIconName } from "../../services/core";
    import withBadge from "../WithBadge/withBadge";
    import styles from "./styles";
    
    @withBadge(1)
    export default class BadgedCart extends PureComponent {
      render() {
        return (
          <Icon
            type="ionicon"
            name={getIconName("cart")}
            containerStyle={styles.iconRight}
            onPress={() => {
              // Nothing.
            }}
          />
        );
      }
    }
    

    我得到一个错误:

    [ts]
    Unable to resolve signature of class decorator when called as an expression.
      Type 'null' is not assignable to type 'void | typeof BadgedCart'. [1238]
    

    JSX.Element 或 ReactElement<any> ,但唯一有效的方法就是 any

    编辑: Praveen 建议)至 typeof PureComponent 错误 @withBadge(1) 更改:

    [ts]
    Unable to resolve signature of class decorator when called as an expression.
      Type 'typeof PureComponent' is not assignable to type 'typeof BadgedOrders'.
        Type 'PureComponent<any, any, any>' is not assignable to type 'BadgedOrders'.
          Types of property 'render' are incompatible.
            Type '() => ReactNode' is not assignable to type '() => Element'.
              Type 'ReactNode' is not assignable to type 'Element'.
                Type 'undefined' is not assignable to type 'Element'. [1238]
    

    PureComponent

        class BadgedComponent extends Component<P> {
          render() {
            return (
              <React.Fragment>
                <WrappedComponent {...this.props} />
                {!hidden && <Badge value={value} />}
              </React.Fragment>
            );
          }
        };
    

    抛出错误:

    [ts]
    Type '(WrappedComponent: ComponentClass<P, any>) => typeof BadgedComponent' is not assignable to type '(WrappedComponent: ComponentClass<P, any>) => PureComponent<{}, {}, any>'.
      Type 'typeof BadgedComponent' is not assignable to type 'PureComponent<{}, {}, any>'.
        Property 'context' is missing in type 'typeof BadgedComponent'. [2322]
    
    1 回复  |  直到 7 年前
        1
  •  5
  •   Titian Cernicova-Dragomir    7 年前

    第一个问题是 P 未处于可以推断的位置。既然是开着的 withBadge 而那个电话不会包含它。

    void 或与输入类相同的类型:

    declare type ClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction | void;
    

    这意味着装饰者签名不能被删除 (WrappedComponent: ComponentClass<P>) => ReactNode ,当它返回时 ReactNode . 不可能 (WrappedComponent: ComponentClass<P>) => ComponentClass<P> 因为它不会返回与传入的内容完全相同的结果。一个解决方案是对编译器撒谎,然后声明我们返回

    class Badge extends React.Component<{ value: number }> { 
    
    }
    
    function withBadge(
    value: number,
    hidden: boolean = value === 0
    ): <P extends object>(WrappedComponent: ComponentClass<P>) => void {
    return <P extends object>(WrappedComponent: ComponentClass<P>) =>
        class BadgedComponent extends Component<P> {
        render() {
            return (
            <React.Fragment>
                <WrappedComponent {...this.props} />
                {!hidden && <Badge value={value} />}
            </React.Fragment>
            );
        }
        };
    }
    
    @withBadge(1)
    export default class BadgedCart extends PureComponent {
        render() {
            return (
            <div />
            );
        }
    }
    

    您可能会考虑使用装饰函数来支持一个简单的函数调用:

    class Badge extends React.Component<{ value: number }> { 
    
    }
    
    function withBadge(
        value: number,
        hidden: boolean = value === 0
    ): <P extends object>(WrappedComponent: ComponentClass<P>) => ComponentClass<P> {
    return <P extends object>(WrappedComponent: ComponentClass<P>) =>
        class BadgedComponent extends Component<P> {
            render() {
                return (
                <React.Fragment>
                    <WrappedComponent {...this.props} />
                    {!hidden && <Badge value={value} />}
                </React.Fragment>
                );
            }
        };
    }
    
    const  BadgedCart = withBadge(1)(class extends PureComponent {
        render() {
            return (
            <div />
            );
        }
    });
    export default BadgedCart;
    
    推荐文章