继承Common类并设属性为必填:Required工具类型报错求助
问题原因
Required<T>是TypeScript的类型工具,仅作用于类型层面,而类的extends关键字后面需要的是一个类的构造函数(即“值”层面的实体),不是类型,所以直接写extends Required<Common>会报错“Required未定义”。
简便实现方案
方案一:手动定义必填版基类(最直观)
如果Common的属性不多,直接创建一个继承自Common的子类,将所有可选属性显式声明为必填,同时复用Common的构造逻辑:
class Common { id?: number; name?: string; constructor(props?: Partial<Common>) { Object.assign(this, props); } // Common的其他方法 commonMethod() { console.log("这是Common的通用方法"); } } // 定义必填版基类 class RequiredCommon extends Common { id: number; name: string; constructor(props: Required<Common>) { super(props); // 显式赋值确保类型合规 this.id = props.id; this.name = props.name; } } class A extends Common { // A的自定义属性/方法 extraPropA?: boolean; } class B extends RequiredCommon { // B的自定义属性/方法 extraPropB: string; constructor(props: Required<Common> & { extraPropB: string }) { super(props); this.extraPropB = props.extraPropB; } } // 使用示例 const a = new A({ id: 1 }); // 允许只传部分属性 const b = new B({ id: 2, name: "测试", extraPropB: "自定义" }); // 必须传全所有必填属性
方案二:用装饰器自动生成必填基类(适合属性较多的场景)
如果Common的属性很多,手动写RequiredCommon太繁琐,可以用类装饰器封装逻辑,同时通过类型约束确保编译时校验:
// 装饰器:将基类的可选属性转为必填(编译时+运行时校验) function MakeRequired<T extends new (...args: any[]) => any>(Base: T) { return class extends Base { constructor(...args: ConstructorParameters<typeof Base>) { super(...args); // 运行时校验所有Common的属性是否已赋值 const requiredKeys = Object.keys(new Base()) as Array<keyof InstanceType<T>>; for (const key of requiredKeys) { if (this[key] === undefined) { throw new Error(`属性 ${String(key)} 为必填项`); } } } } as new (props: Required<InstanceType<T>>) => InstanceType<T>; } class Common { id?: number; name?: string; desc?: string; constructor(props?: Partial<Common>) { Object.assign(this, props); } } // 生成必填版基类 const RequiredCommon = MakeRequired(Common); class A extends Common { // ... } class B extends RequiredCommon { // ... } // 编译时会报错,运行时也会抛出异常 // const b = new B({ id: 1 }); // 正确用法 const b = new B({ id: 1, name: "测试", desc: "描述" });
方案三:类型约束+组合(无需继承的场景)
如果不需要完全继承Common的方法,只是复用属性类型,可以直接在B类中用Required<Common>做类型约束,通过组合复用Common的逻辑:
// 先定义接口复用属性类型 interface ICommon { id?: number; name?: string; } class Common implements ICommon { id?: number; name?: string; constructor(props?: Partial<ICommon>) { Object.assign(this, props); } commonMethod() { return "通用方法返回值"; } } class A extends Common { // ... } class B implements Required<ICommon> { id: number; name: string; // 组合Common实例复用方法 private commonInstance = new Common(); constructor(props: Required<ICommon>) { this.id = props.id; this.name = props.name; } // 复用Common的方法 useCommonMethod() { return this.commonInstance.commonMethod(); } }
内容的提问来源于stack exchange,提问作者user19024399
相关产品推荐
相关产品推荐

