TS-基于扩展类的接口的构造函数设置值

时间:2018-10-14 21:20:07

标签: typescript

我有以下示例接口/类

export interface MyErrorI {
    something: boolean;
}

export class MyError extends Error implements MyErrorI {
    public something = false;

    constructor(message: string, key: keyof MyErrorI ) {
        super(message);

        this[key] = true; // this is the code that I want to reuse
    }
}

概念是构造函数根据其关键参数设置其属性的值。

现在我想用另一个类来扩展它:

interface MyNewErrorI extends MyErrorI {
    somethingElse: boolean;
}

export class MyNewError extends MyError implements MyNewErrorI {
    public somethingElse = false;

    constructor(message: string, key: keyof MyNewErrorI) {
        super(message, key);
    }
}

现在,键参数可以具有扩展MyErrorI的接口的属性。由于我实际问题的复杂性,我不想将代码从父类的构造函数复制/粘贴到子类的构造函数。

但是,上面的代码无法正常工作,因为MyError的构造函数需要键MyErrorI。但是,键somethingElseMyNewError的有效属性。

因此,问题是:父类的构造函数是否有可能每次基于其子类调用key来访问super参数? < / p>

我试图做这样的事情,但是它也不起作用:

export class MyError<T extends PaymentErrorI> extends Error implements MyErrorI {
    public something = false;

    constructor(message: string, key: keyof T) {
        super(message);

        this[key] = true;
    }
}

实际的构造函数如下:

constructor(message: string, key: keyof MyErrorI | Array<keyof MyErrorI>, data?: any) {
        super(message);

        if (key instanceof Array) {
            key.forEach((v) => {
                this[v] = true;
            });
        } else {
            this[key] = true;
        }

        this.payload = data;
}

因此,使用super(message, key, data)进行调用可以节省更多的代码行,并使其更易于维护。

或者,我可以使用功能相同的功能吗? 像

const setKeys = <T>(err: T, key: keyof T | Array<keyof T>)

将提供所需的功能。这样,err[key] = true我得到Type 'true' is not assignable to type 'T[keyof T]'

谢谢!

1 个答案:

答案 0 :(得分:1)

与构造函数分离的函数可能是可行的方法,因为构造函数无法覆盖预期的this类型或使用特殊的this类型来引用要创建的子类的类型构造,并且仅仅为了进行键设置而添加类型参数将非常笨拙。函数签名的问题在于,您尚未确保传入的T的键具有布尔值,因此将true分配给它们可能无效。函数定义应如下所示:

const setKeys = <K extends keyof any>(err: {[P in K]: boolean}, key: K | Array<K>) => {
    if (key instanceof Array) {
        key.forEach((v) => {
            err[v] = true;
        });
    } else {
        err[key] = true;
    }
};

或者您可以将setKeys设为MyError的方法,因为方法(不同于构造函数)可以覆盖预期的this类型:

export class MyError extends Error implements MyErrorI {
    // ...
    setKeys<K extends keyof any>(this: { [P in K]: boolean }, key: K | Array<K>) { 
        if (key instanceof Array) {
            key.forEach((v) => {
                this[v] = true;
            });
        } else {
            this[key] = true;
        }
    }
}