1. 仅有 getValue(): T
方法时的类型兼容性分析
- 赋值操作:
- 在TypeScript中,当一个类只有读取操作(如
getValue
)时,它遵循协变规则。也就是说,GenericClass<SubType>
是 GenericClass<SuperType>
的子类型。可以将 GenericClass<SubType>
的实例赋值给 GenericClass<SuperType>
类型的变量。
- 例如:
class SuperType {}
class SubType extends SuperType {}
class GenericClass<T> {
getValue(): T {
// 这里只是示例,实际返回值需要符合类型
return null as any;
}
}
let subClass: GenericClass<SubType> = new GenericClass<SubType>();
let superClass: GenericClass<SuperType> = subClass; // 这种赋值是允许的
- 函数参数传递:
- 在函数参数位置,如果一个函数接受
GenericClass<SuperType>
类型的参数,那么也可以传递 GenericClass<SubType>
的实例。这同样是因为协变规则。
- 例如:
function acceptSuperTypeClass(cls: GenericClass<SuperType>) {
// 函数体
}
let subClass: GenericClass<SubType> = new GenericClass<SubType>();
acceptSuperTypeClass(subClass); // 这种传递是允许的
2. 增加 setValue(value: T)
方法后的类型兼容性分析
- 赋值操作:
- 当类增加了
setValue
这样的写入操作后,它遵循逆变规则。此时,GenericClass<SuperType>
是 GenericClass<SubType>
的子类型,与只有 getValue
方法时情况相反。将 GenericClass<SuperType>
的实例赋值给 GenericClass<SubType>
类型的变量是允许的,但反过来不行。
- 例如:
class SuperType {}
class SubType extends SuperType {}
class GenericClass<T> {
getValue(): T {
// 这里只是示例,实际返回值需要符合类型
return null as any;
}
setValue(value: T) {
// 这里只是示例,实际实现可能不同
}
}
let superClass: GenericClass<SuperType> = new GenericClass<SuperType>();
let subClass: GenericClass<SubType> = superClass; // 这种赋值会报错
let superToSub: GenericClass<SubType> = new GenericClass<SuperType>(); // 这种赋值也会报错
let subClass2: GenericClass<SubType> = new GenericClass<SubType>();
let subToSuper: GenericClass<SuperType> = subClass2; // 这种赋值现在是不允许的
- 函数参数传递:
- 在函数参数位置,如果一个函数接受
GenericClass<SubType>
类型的参数,那么可以传递 GenericClass<SuperType>
的实例。这是由于逆变规则。
- 例如:
function acceptSubTypeClass(cls: GenericClass<SubType>) {
// 函数体
}
let superClass: GenericClass<SuperType> = new GenericClass<SuperType>();
acceptSubTypeClass(superClass); // 这种传递现在是允许的
总结
- 当
GenericClass
仅有 getValue
方法时,由于协变规则,GenericClass<SubType>
可视为 GenericClass<SuperType>
的子类型,在赋值和函数参数传递上遵循协变特性。
- 当
GenericClass
增加了 setValue
方法后,由于逆变规则,GenericClass<SuperType>
可视为 GenericClass<SubType>
的子类型,赋值和函数参数传递的兼容性发生反转。这是因为写入操作(setValue
)要求类型更加严格,需要确保传入的值与预期类型完全兼容或为其父类型,以避免类型安全问题。