Flow类型孙类继承问题:基类到子类成功,子类到孙类失败
核心类型兼容性逻辑
先拆解各环节的类型匹配逻辑:
base的类型是(options: BaseType) => void,即fnType<BaseType>。调用extend<ChildOneType>(base)时,函数参数的逆变规则生效:接受父类型参数的函数,可以兼容接受子类型参数的函数需求。因为ChildOneType包含BaseType的所有属性,传给期望BaseType的函数是安全的,所以这一步没问题。childOne的类型是fnType<ChildOneType>(即(options: ChildOneType) => void)。当你调用extend<ChildTwoType>(childOne)时,extend要求传入的parent是fnType<ChildTwoType>(即(options: ChildTwoType) => void)。这时候逆变规则不支持反向兼容:ChildOneType是ChildTwoType的父类型,接受ChildOneType参数的函数,无法兼容接受ChildTwoType参数的要求——类型系统认为,childOne的函数只处理包含one属性的对象,而ChildTwoType多了two属性,强行传入会违反类型约束(尽管你的代码逻辑里没用到two,但静态类型检查是基于类型定义的)。
错误根源
你的extend函数定义是:
function extend<T: BaseType>(parent: fnType<T>): fnType<T>{ return (options: T): void => { return parent(options); } }
它要求传入的parent必须严格匹配fnType<T>,也就是参数类型恰好是T。当你指定T为ChildTwoType时,childOne的参数类型是ChildOneType,缺少ChildTwoType的two属性,类型检查器自然会报错。
修复思路(可选)
如果要支持孙类继承,需要放宽extend的参数约束,让父函数可以接受T的子类型参数。比如调整泛型约束:
// 修改extend的参数类型,允许父函数接受T的父类型参数 function extend<T extends BaseType>(parent: fnType<BaseType>): fnType<T> { return (options: T): void => { parent(options); }; }
或者利用更灵活的泛型约束,让父函数的参数类型是T的超类型:
function extend<T extends BaseType, U extends BaseType>(parent: fnType<U>): fnType<T> where T extends U { return (options: T): void => { parent(options); }; }
内容的提问来源于stack exchange,提问作者anson

