为什么TypeScript抱怨我的抽象类成员的实现?

时间:2019-02-12 08:50:47

标签: typescript abstract-class abstract

以下是我的自定义类型:

type KeyMap<T> = { [K in keyof T]: keyof Pick<T, K> }

接着是一个用于自定义类型的简单界面:

interface MyInterface {
    a: string;
    b: string;
}

当我的类型的变量在类之外定义时,TypeScript很高兴:

const member: KeyMap<MyInterface> = {
    a: 'a',
    b: 'b'
}

但是,当我使用类型为KeyMap的抽象成员定义一个抽象类并尝试实现它时,它将无法正常工作。例如:

abstract class BaseClass<T> {
    protected abstract member: KeyMap<T>
    protected abstract method: () => void;
}

class DerivedClass extends BaseClass<MyInterface> {
    // TypeScript reports that property 'a' is not compatible with '"a"'
    protected member = { 
        a: 'a', 
        b: 'b'
    };

    protected method = () => console.log('');
}

直接在抽象或派生类中定义成员似乎可行。例如:

abstract class BaseClass {
    public member: KeyMap<MyInterface> = {
        a: 'a', 
        b: 'b'
    }
    protected abstract method: () => void;
}

class DerivedClass extends BaseClass {
    public derivedMember: KeyMap<MyInterface> = {
        a: 'a', 
        b: 'b'
    }

    protected method = () => console.log('');
}

将成员更改为其他类型也是如此:

abstract class BaseClass<T> {
    protected abstract member: { c: string, d: string };
    protected abstract method: () => void;
}

class DerivedClass extends BaseClass<MyInterface> {
    protected member = { 
        c: 'c', 
        d: 'd'
    };

    protected method = () => console.log('');
}

为什么TypeScript在派生类中member的实现在类之外工作并且未标记为抽象时将其报告为错误?

TypeScript Playground Link

1 个答案:

答案 0 :(得分:1)

类成员是类型,而与基类中的内容无关,只有这样,派生类才会被检查与基类的兼容性。由于成员是根据初始化值键入的,因此typescript不会将文字类型用于属性类型(只有某些地方TS不会扩展文字类型,这也不是其中之一)

您可以做的最好的想法就是为成员使用一个明确的类型注释,就像您已经说过的在问题中尝试过的那样:

class DerivedClass extends BaseClass<MyInterface> {
    protected member: KeyMap<MyInterface> = { 
        a: 'a', 
        b: 'b'
    };

    protected method = () => console.log('');
}