MST

星途 面试题库

面试题:TypeScript类型兼容性在泛型与逆变、协变中的深度剖析

在TypeScript泛型中,假设我们有一个泛型接口`Contravariant<T>`表示逆变,`Covariant<T>`表示协变,定义如下:`interface Contravariant<T> { (arg: T): void; }`,`interface Covariant<T> { (): T; }`。请分别举例说明在什么场景下会用到逆变和协变,并且解释为什么在这些场景下使用逆变或协变能够保证类型安全,通过具体代码示例详细阐述。
34.3万 热度难度
前端开发TypeScript

知识考点

AI 面试

面试题答案

一键面试

逆变(Contravariance)

  1. 场景:函数参数类型的兼容性。当一个函数期望接收一个更具体类型的参数,但实际传入一个更宽泛类型的函数时,逆变可以确保类型安全。
  2. 代码示例
interface Contravariant<T> { 
    (arg: T): void; 
}

// 定义一个具体类型的函数
function handleString(str: string): void {
    console.log(str);
}

// 定义一个宽泛类型的函数
function handleAny(arg: any): void {
    console.log(arg);
}

// 逆变示例,这里宽泛类型函数可以赋值给具体类型函数的位置
let stringHandler: Contravariant<string> = handleAny; 
  1. 类型安全解释:在逆变场景中,因为handleAny可以处理任何类型,那么它一定可以处理string类型。如果反过来将handleString赋值给期望Contravariant<any>的地方就会报错,因为handleString不能处理所有类型,只能处理string类型,这保证了类型安全。

协变(Covariance)

  1. 场景:函数返回值类型的兼容性。当一个函数期望返回一个更宽泛类型的值,但实际返回一个更具体类型的值时,协变可以确保类型安全。
  2. 代码示例
interface Covariant<T> { 
    (): T; 
}

// 定义一个返回具体类型的函数
function getString(): string {
    return 'Hello';
}

// 定义一个返回宽泛类型的函数
function getAny(): any {
    return 'Hello';
}

// 协变示例,具体类型函数可以赋值给宽泛类型函数的位置
let anyGetter: Covariant<any> = getString; 
  1. 类型安全解释:在协变场景中,因为getString返回string类型,stringany的子类型,所以可以将getString赋值给期望返回any类型的函数位置。如果反过来将getAny赋值给期望Covariant<string>的地方就会报错,因为getAny返回的不一定是string类型,这保证了类型安全。