简体   繁体   English

在打字稿中抽象通用Container类的子项的装饰器

[英]Decorator for children of abstract generic Container class in Typescript

I'm having trouble with Typescript generics. 我在使用Typescript泛型时遇到了麻烦。 I'm using Typescript 2.6 . 我正在使用Typescript 2.6

The basic idea is that I want to create a MobX store that exposes a class decorator adding basic authentication check, and that decorator takes a class type derived from the abstract generic Container class (a React Router route container, for example). 基本思想是我想创建一个暴露类装饰器的MobX存储库,添加基本的身份验证检查,并且装饰器采用从抽象通用Container类派生的类类型(例如,React Router路由容器)。

Here is the code leading to the issue: 以下是导致该问题的代码:

interface Newable<T, U = any> {
  new (...args: U[]): T;
}

function withAuth<TContainer extends Container<TProps, TState>, TProps extends Container.Props, TState>(ctor: Newable<TContainer>): Newable<TContainer> {
  return class WithAuth extends ctor {
    public async componentWillMount() {
      await this.props.stores.authentication.tryLoggingIn();
      super.componentWillMount();
    }

    public async componentWillUpdate() {
      await this.props.stores.authentication.tryLoggingIn();
      super.componentWillUpdate();
    }

    public render(): React.ReactNode {
      return super.render();
    }
  };
}

Both the TProps and TState generic parameters can be redefined by the derived class, as they may have more React props or a complex state. TPropsTState泛型参数都可以由派生类重新定义,因为它们可能有更多的React道具或复杂状态。


The error messages I get from the Typescript compiler: 我从Typescript编译器得到的错误消息:

Type 'typeof WithAuth' is not assignable to type 'Newable<TContainer, any>'. Type 'WithAuth' is not assignable to type 'TContainer'. (line 6)
Base constructor return type 'TContainer' is not a class or interface type. (line 6)
Property 'props' does not exist on type 'WithAuth'. (line 8)
Property 'props' does not exist on type 'WithAuth'. (line 14)

Removing the return type of the withAuth function leads to this error: 删除withAuth函数的返回类型会导致此错误:

Base constructor return type 'TContainer' is not a class or interface type.

Here is the relevant code for the Container class (simplified, it contains a little bit more stuff): 这是Container类的相关代码(简化,它包含更多东西):

abstract class Container<T extends Container.Props = Container.Props, U extends React.ComponentState = {}> extends React.Component<T, U> {
  public abstract render(): React.ReactNode;
}

namespace Container {
  export type Props = React.Props<any>; // TODO: typings
}

What I don't get is, even using a non-generic class instead of Container leads to the 我没有得到的是,即使使用非泛型类而不是容器导致

Base constructor return type 'TContainer' is not a class or interface type.

error. 错误。 However, as you can see in the generic parameter declaration, TContainer IS DERIVED from a class. 但是,正如您在泛型参数声明中所看到的,TContainer IS DERIVED来自一个类。 From what I get, this shouldn't be an issue. 从我得到的,这应该不是一个问题。

So my question is, how can I create a class decorator to the Container<TProps, TState> that would add authentication checks to componentWillMount and componentWillUpdate ? 所以我的问题是, 我如何为Container<TProps, TState>创建一个类装饰器,它将对componentWillMountcomponentWillUpdate添加身份验证检查?

Thanks a bunch! 谢谢你!

You are trying to use mixins, which are described here . 您正在尝试使用的混入,其说明这里 The way it works is pretty particular, the class that will be augmented must be passed in as a type parameter, which can be constrained to extend the abstract class. 它的工作方式非常特殊,要扩充的类必须作为类型参数传入,可以约束它来扩展抽象类。 Note that since we mandate the class will have a callable constructor, the class passed to withAuth can't be Container but rather a class that is derived from Container and implements the abstract methods already. 请注意,由于我们要求类具有可调用的构造函数,因此传递给withAuth的类不能是Container ,而是从Container派生的类,并且已经实现了抽象方法。

abstract class Container<T extends Container.Props = Container.Props, U extends React.ComponentState = {}> extends React.Component<T, U> {
    public abstract render(): React.ReactNode;
}

namespace Container {
    export type Props = {
        stores: any
    };
}

interface Newable<T, U = any> {
    new(...args: U[]): T;
}

function withAuth<TCtor extends Newable<Container<Container.Props, any>>>(ctor: TCtor) {
    return class WithAuth extends ctor {
        public async componentWillMount() {
            await this.props.stores.authentication.tryLoggingIn();
            this.componentWillMount();
        }

        public async componentWillUpdate() {
            await this.props.stores.authentication.tryLoggingIn();
            this.componentWillUpdate();
        }

        public render(): React.ReactNode {
            return this.render();
        }
    };
}

class NewComponent extends Container< Container.Props & { otherProp: string}, any> {
    public render(): React.ReactNode {
        // Actual implementation 
        throw new Error("Method not implemented.");
    }

}
const NewComponentWitAuth = withAuth(NewComponent);

let witAuth = <NewComponentWitAuth otherProp="" stores={null}  /> // props type is preserved

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM