MST

星途 面试题库

面试题:TypeScript 方法重写与类型兼容性及运行时行为

在 TypeScript 中,考虑一个场景,基类有一个方法接受特定类型参数并返回特定类型。子类重写该方法时,参数类型放宽(协变)或返回类型收紧(逆变),在遵循 TypeScript 类型系统规则的前提下,分析这种重写在运行时可能出现的问题,并通过代码示例展示如何在保证类型安全的同时处理这种情况。
15.7万 热度难度
前端开发TypeScript

知识考点

AI 面试

面试题答案

一键面试

问题分析

  1. 参数类型协变:在运行时,如果子类方法放宽了参数类型,可能会导致传入不符合基类预期的数据,从而引发运行时错误。例如,基类方法期望接收一个 string 类型参数,子类放宽为 any 类型,调用者可能传入一个非 string 类型数据,在子类方法中按 string 相关逻辑处理时就会出错。
  2. 返回类型逆变:虽然在类型系统中允许返回类型收紧,但如果在运行时调用者按照基类返回类型的预期使用返回值,而子类返回的实际类型过于特殊,可能导致调用者使用时出现类型不匹配问题。例如,基类返回 number 类型,子类返回 1 这个字面量类型,调用者可能会对返回值进行数学运算,但如果返回值是 1 这个字面量类型,某些运算可能不被支持(比如 ++ 操作在严格模式下对字面量 1 可能会有问题)。

代码示例

// 基类
class Base {
    process(data: string): number {
        return data.length;
    }
}

// 子类重写方法,参数类型协变
class Child1 extends Base {
    process(data: any): number {
        if (typeof data ==='string') {
            return data.length;
        }
        return 0;
    }
}

// 子类重写方法,返回类型逆变
class Child2 extends Base {
    process(data: string): 1 {
        return 1;
    }
}

// 使用示例
function useBase(base: Base) {
    const result = base.process('test');
    console.log(result);
}

const child1 = new Child1();
const child2 = new Child2();

useBase(child1);
useBase(child2);

在上述代码中,Child1 类重写 process 方法时放宽了参数类型,通过在方法内部进行类型检查来保证运行时不会因为参数类型问题出错。Child2 类重写 process 方法时收紧了返回类型,虽然类型系统允许,但调用者在使用返回值时要注意其实际类型。在 useBase 函数中统一使用基类来调用 process 方法,展示了如何在保证类型安全的同时处理这种情况。