面试题答案
一键面试类继承体系设计
在TypeScript中,我们可以这样设计类继承体系,实现父类和子类方法使用静态类型和动态类型达成多态:
// 父类使用静态类型
class Parent {
// 父类方法接受静态类型参数并返回静态类型
public methodWithStaticTypes(param: string): number {
return param.length;
}
}
// 子类使用动态类型
class Child extends Parent {
// 重写父类方法,使用动态类型参数并返回动态类型
public methodWithStaticTypes(param: any): any {
if (typeof param === 'number') {
return param * 2;
}
return param;
}
}
TypeScript类型检查机制工作原理
- 静态类型检查:TypeScript在编译阶段进行静态类型检查。当一个变量被声明为某种类型,TypeScript会确保该变量的使用符合声明的类型。对于上述代码,在编译时,TypeScript会检查
Parent
类中methodWithStaticTypes
方法,确保传入的参数是string
类型,返回值是number
类型。 - 子类重写方法检查:当子类重写父类方法时,TypeScript会检查子类方法的参数和返回值类型是否与父类方法兼容。在这个例子中,虽然子类
Child
的methodWithStaticTypes
方法参数和返回值使用了any
类型(动态类型),但由于any
类型可以兼容任何类型,所以在类型检查时不会报错。
可能遇到的问题
- 类型安全问题:使用
any
类型绕过了TypeScript的大部分类型检查,可能会导致运行时错误。例如,如果在Child
类的methodWithStaticTypes
方法中期望param
是number
类型,但实际传入了string
类型,就会在运行时抛出错误。 - 代码可读性和可维护性问题:
any
类型使代码失去了类型信息,其他开发者难以理解代码的意图和参数、返回值的预期类型,增加了维护成本。
解决方法
- 尽量避免使用
any
类型:如果可能,使用更具体的类型。例如,在Child
类的methodWithStaticTypes
方法中,可以使用联合类型来限制参数类型,如param: number | string
,这样既能保持一定的灵活性,又能保证类型安全。
class Child extends Parent {
public methodWithStaticTypes(param: number | string): number | string {
if (typeof param === 'number') {
return param * 2;
}
return param.length;
}
}
- 使用类型断言:在需要处理动态类型时,可以使用类型断言来明确告诉TypeScript某个值的类型。例如:
class Child extends Parent {
public methodWithStaticTypes(param: any): any {
if (typeof param === 'number') {
return param * 2;
}
// 使用类型断言
const strParam = param as string;
return strParam.length;
}
}
这样可以在一定程度上保持类型安全,同时利用动态类型的灵活性。