TypeScript子类属性类型继承疑问:为何Child的property可随意加键?
问题描述
以下TypeScript代码示例中,Child类的property属性未被严格类型限制,能够添加任意额外键:
type Properties<T> = { [K in keyof T]: boolean; }; class Parent<T> { property: Properties<T> = {} as Properties<T>; } class Child extends Parent<{someKey: boolean}> { property = { someKey: true, somethingElse: "hello", }; }
若在构造函数中初始化该属性,或在Child类中显式定义其类型,均可正常实现严格类型检查。但代码库中有大量多层级的Child类,上述两种方式会产生大量冗余代码,现需了解该现象的原因。
原因分析
- 属性初始化的类型推断规则:子类直接赋值初始化属性时,TypeScript会先根据赋值的字面量推断属性的具体类型(此处为
{someKey: boolean; somethingElse: string}),再和父类的属性类型做兼容性校验。由于TypeScript的结构类型系统允许子类型包含额外属性(父类型是子类型的超集即可),所以这个带额外键的类型被判定为符合父类Properties<{someKey: boolean}>的要求,不会触发错误。 - 显式类型/构造函数初始化的区别:
- 若在子类显式声明
property的类型为Properties<{someKey: boolean}>,TypeScript会直接用该类型约束初始化值,禁止额外属性。 - 在构造函数中初始化时,属性类型直接继承父类定义,赋值操作是对已有明确类型的属性进行修改,会严格遵循父类的类型约束,不允许添加额外键。
- 若在子类显式声明
- 泛型父类的属性继承特性:父类
property的类型依赖泛型参数T,子类继承时虽指定了T的具体类型,但直接初始化属性的行为会让TypeScript优先使用初始化值的推断类型,而非继承自父类的属性类型。只有显式指定类型或通过构造函数赋值(属于对继承属性的修改),才会沿用父类的泛型约束。
内容的提问来源于stack exchange,提问作者matiss.andersons
相关产品推荐
相关产品推荐

