我遇到了Typescript泛型问题。 我正在使用Typescript 2.6 。
基本思想是我想创建一个暴露类装饰器的MobX存储库,添加基本的身份验证检查,而装饰器接受从抽象通用Container
类派生的类类型(React Router路由容器,例如)。
以下是导致此问题的代码:
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();
}
};
}
派生类可以重新定义TProps
和TState
泛型参数,因为它们可能有更多的React道具或复杂状态。
我从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)
删除withAuth函数的返回类型会导致此错误:
Base constructor return type 'TContainer' is not a class or interface type.
以下是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
}
我没有得到的是,即使使用非泛型类而不是Container导致
Base constructor return type 'TContainer' is not a class or interface type.
错误。但是,正如您在泛型参数声明中所看到的,TContainer IS DERIVED来自一个类。从我得到的,这应该不是一个问题。
所以我的问题是,如何为Container<TProps, TState>
创建一个类装饰器,将componentWillMount
和componentWillUpdate
添加身份验证检查?
非常感谢!
答案 0 :(得分:2)
您正在尝试使用mixins,其描述为here。它的工作方式非常特殊,要扩充的类必须作为类型参数传入,可以约束它来扩展抽象类。请注意,由于我们要求类具有可调用的构造函数,因此传递给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