当前位置: 首页 > news >正文

TypeScript 面试题及详细答案 100题 (61-70)-- 泛型(Generics)

前后端面试题》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,SQL,Linux… 。

前后端面试题-专栏总目录

在这里插入图片描述

文章目录

  • 一、本文面试题目录
      • 61. 什么是泛型?它解决了什么问题?举例说明其核心价值。
      • 62. 如何定义泛型函数?如何指定泛型的默认类型?
      • 63. 如何定义泛型接口和泛型类?
      • 64. 什么是泛型约束?如何用`extends`实现泛型约束?举例说明。
      • 65. 如何对泛型参数进行“多约束”(即同时满足多个条件)?
      • 66. `keyof`操作符的作用是什么?如何结合泛型使用?
      • 67. 泛型工具类型`Partial`、`Required`、`Pick`、`Omit`的作用是什么?如何实现一个简易版`Partial`?
      • 68. 什么是泛型的“协变”和“逆变”?`in`关键字如何影响泛型的变异性?
      • 69. 如何用泛型实现一个“深拷贝”函数的类型定义?
      • 70. 泛型与联合类型结合时,如何避免“分布式条件类型”的副作用?
  • 二、100道TypeScript面试题目录列表

一、本文面试题目录

61. 什么是泛型?它解决了什么问题?举例说明其核心价值。

  • 原理说明
    泛型(Generics)是 TypeScript 中用于创建可复用、类型安全的组件的工具,它允许在定义函数、接口或类时不预先指定具体类型,而是在使用时动态指定。
    它解决的核心问题是:代码复用与类型约束的矛盾。没有泛型时,要么通过 any 牺牲类型安全以实现复用,要么为每种类型重复编写逻辑。泛型通过“类型参数”实现了“同一份代码适配多种类型”,同时保持类型检查。

  • 示例代码

    // 不使用泛型:要么丢失类型检查(any),要么重复实现
    function identityAny(arg: any): any {return arg;
    }
    const num1: number = identityAny(123); // 实际类型为any,无类型约束// 使用泛型:复用逻辑且保留类型
    function identity<T>(arg: T): T {return arg;
    }
    const num2: number = identity(123); // 正确,T被推断为number
    const str: string = identity("hello"); // 正确,T被推断为string
    
  • 核心价值

    • 类型安全:避免 any 导致的类型丢失。
    • 代码复用:一份逻辑适配多种类型(如通用工具函数、容器类)。
    • 灵活性:使用时动态指定类型,兼顾扩展性与约束性。

62. 如何定义泛型函数?如何指定泛型的默认类型?

  • 原理说明
    泛型函数通过在函数名后添加 <类型参数> 定义,类型参数可在参数、返回值中使用。
    泛型默认类型允许为类型参数指定默认值,当未显式或隐式指定类型时,使用默认类型。

  • 示例代码

    // 1. 基础泛型函数定义
    function logAndReturn<T>(value: T): T {console.log(value);return value;
    }
    logAndReturn<number>(123); // 显式指定T为number
    logAndReturn("hello"); // 隐式推断T为string// 2. 泛型默认类型(使用 = 指定)
    function createArray<T = string>(length: number, value: T): T[] {return Array(length).fill(value);
    }
    createArray(3, "a"); // T默认为string,返回string[]
    createArray<number>(3, 0); // 显式指定T为number,返回number[]
    

63. 如何定义泛型接口和泛型类?

  • 原理说明
    泛型接口和类通过在名称后添加 <类型参数> 定义,类型参数可用于约束接口的属性/方法或类的成员。

  • 示例代码

    // 1. 泛型接口
    interface Container<T> {value: T;setValue: (v: T) => void;
    }
    // 使用时指定类型
    const numContainer: Container<number> = {value: 0,setValue: (v) => numContainer.value = v
    };// 2. 泛型类
    class Stack<T> {private items: T[] = [];push(item: T): void {this.items.push(item);}pop(): T | undefined {return this.items.pop();}
    }
    const stringStack = new Stack<string>();
    stringStack.push("a"); // 正确
    stringStack.push(123); // 错误:类型number不符合string
    

64. 什么是泛型约束?如何用extends实现泛型约束?举例说明。

  • 原理说明
    泛型约束(Generic Constraints)用于限制类型参数的范围,确保其包含特定属性或方法,避免在使用泛型时访问不存在的成员。通过 extends 关键字实现,指定类型参数必须满足的条件。

  • 示例代码

    // 约束T必须包含length属性
    interface HasLength {length: number;
    }
    // T extends HasLength:确保T有length属性
    function getLength<T extends HasLength>(arg: T): number {return arg.length; // 安全访问length
    }getLength("hello"); // 正确:string有length
    getLength([1, 2, 3]); // 正确:数组有length
    getLength(123); // 错误:number无length属性
    

65. 如何对泛型参数进行“多约束”(即同时满足多个条件)?

  • 原理说明
    多约束指类型参数需同时满足多个条件,可通过 extends 结合交叉类型(&)实现,即 T extends A & B & C 表示 T 必须同时符合 A、B、C 的约束。

  • 示例代码

    interface HasId {id: number;
    }
    interface HasName {name: string;
    }
    // T必须同时满足HasId和HasName
    function logEntity<T extends HasId & HasName>(entity: T): void {console.log(`ID: ${entity.id}, Name: ${entity.name}`);
    }logEntity({ id: 1, name: "test" }); // 正确:满足两个约束
    logEntity({ id: 1 }); // 错误:缺少name(不满足HasName)
    logEntity({ name: "test" }); // 错误:缺少id(不满足HasId)
    

66. keyof操作符的作用是什么?如何结合泛型使用?

  • 原理说明
    keyof 用于获取某个类型的所有键名,返回一个由键名组成的联合类型。结合泛型时,可动态约束参数为对象的键,实现类型安全的属性访问。

  • 示例代码

    // 1. keyof基础用法
    interface User {name: string;age: number;
    }
    type UserKeys = keyof User; // 等价于 "name" | "age"// 2. 结合泛型:安全访问对象属性
    function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {return obj[key]; // 确保key是T的有效键
    }const user: User = { name: "Alice", age: 30 };
    getProperty(user, "name"); // 正确:返回string
    getProperty(user, "age"); // 正确:返回number
    getProperty(user, "email"); // 错误:"email"不是User的键
    

67. 泛型工具类型PartialRequiredPickOmit的作用是什么?如何实现一个简易版Partial

  • 原理说明
    泛型工具类型是 TypeScript 内置的基于泛型的类型转换工具,用于快速生成新类型:

    • Partial<T>:将 T 的所有属性转为可选。
    • Required<T>:将 T 的所有属性转为必填(与 Partial 相反)。
    • Pick<T, K>:从 T 中选取键为 K 的属性组成新类型。
    • Omit<T, K>:从 T 中排除键为 K 的属性组成新类型(与 Pick 相反)。
  • 示例代码

    interface User {id: number;name: string;age: number;
    }// 内置工具类型示例
    type PartialUser = Partial<User>; // { id?: number; name?: string; age?: number }
    type RequiredUser = Required<PartialUser>; // 恢复为User(所有属性必填)
    type UserName = Pick<User, "name">; // { name: string }
    type UserWithoutAge = Omit<User, "age">; // { id: number; name: string }// 简易版Partial实现
    type MyPartial<T> = {[P in keyof T]?: T[P]; // 遍历T的所有键,转为可选
    };
    type MyPartialUser = MyPartial<User>; // 效果同Partial<User>
    

68. 什么是泛型的“协变”和“逆变”?in关键字如何影响泛型的变异性?

  • 原理说明
    泛型的“变异性”描述类型参数的子类型关系如何影响泛型类型的子类型关系:

    • 协变(Covariant):若 A extends B,则 Generic<A> extends Generic<B>(子类型关系保留)。
    • 逆变(Contravariant):若 A extends B,则 Generic<B> extends Generic<A>(子类型关系反转)。
    • TypeScript 中,默认情况下:
      • 泛型接口/类的属性是协变的。
      • 函数参数是逆变的(在 strictFunctionTypes 开启时)。
    • in 关键字用于标记泛型参数为“逆变位置”(通常用于函数参数),强制其逆变行为。
  • 示例代码

    // 协变示例(数组是协变的)
    type Animal = { name: string };
    type Dog = Animal & { bark: () => void };
    const dogs: Dog[] = [{ name: "Buddy", bark: () => {} }];
    const animals: Animal[] = dogs; // 正确:Dog[] 是 Animal[] 的子类型(协变)// 逆变示例(函数参数是逆变的)
    type AnimalHandler = (a: Animal) => void;
    type DogHandler = (d: Dog) => void;
    const animalHandler: AnimalHandler = (a) => console.log(a.name);
    const dogHandler: DogHandler = (d) => d.bark();// 当strictFunctionTypes开启时:
    const handler: DogHandler = animalHandler; // 正确:AnimalHandler 是 DogHandler 的子类型(逆变)
    const handler2: AnimalHandler = dogHandler; // 错误:DogHandler 不是 AnimalHandler 的子类型
    

69. 如何用泛型实现一个“深拷贝”函数的类型定义?

  • 原理说明
    深拷贝函数需递归复制对象的所有层级,类型定义需通过泛型递归处理嵌套结构,区分基本类型、数组、对象等。

  • 示例代码

    type DeepClone<T> = T extends number | string | boolean | null | undefined | symbol | bigint ? T // 基本类型直接返回: T extends Array<infer U> ? Array<DeepClone<U>> // 数组:递归处理元素: { [K in keyof T]: DeepClone<T[K]> }; // 对象:递归处理属性function deepClone<T>(value: T): DeepClone<T> {if (typeof value !== "object" || value === null) {return value as DeepClone<T>;}if (Array.isArray(value)) {return value.map(deepClone) as DeepClone<T>;}const cloned: Record<string, any> = {};for (const key in value) {cloned[key] = deepClone(value[key]);}return cloned as DeepClone<T>;
    }// 测试
    const obj = { a: 1, b: { c: "hello" }, d: [1, 2] };
    const cloned = deepClone(obj);
    // cloned类型:{ a: number; b: { c: string }; d: number[] }(与原对象类型一致)
    

70. 泛型与联合类型结合时,如何避免“分布式条件类型”的副作用?

  • 原理说明
    分布式条件类型指:当泛型参数为联合类型 A | B | C 时,条件类型 T extends U ? X : Y 会自动分发为 (A extends U ? X : Y) | (B extends U ? X : Y) | (C extends U ? X : Y)。若需避免这种分发行为,可通过将泛型参数包裹在元组中([T] extends [U])阻止分布式处理。

  • 示例代码

    // 分布式条件类型(默认行为)
    type Distributed<T> = T extends string ? "string" : "other";
    type Result1 = Distributed<string | number>; // "string" | "other"(分发处理)// 避免分布式行为(用元组包裹)
    type NonDistributed<T> = [T] extends [string] ? "string" : "other";
    type Result2 = NonDistributed<string | number>; // "other"(整体判断,不分发)// 应用场景:判断类型是否完全匹配联合类型
    type IsExactStringUnion<T> = [T] extends [string] ? true : false;
    type Test1 = IsExactStringUnion<string>; // true
    type Test2 = IsExactStringUnion<string | number>; // false(避免了分发导致的错误判断)
    

二、100道TypeScript面试题目录列表

文章序号TypeScript面试题100道
1TypeScript面试题及详细答案100道(01-10)
2TypeScript面试题及详细答案100道(11-20)
3TypeScript面试题及详细答案100道(21-30)
4TypeScript面试题及详细答案100道(31-40)
5TypeScript面试题及详细答案100道(41-50)
6TypeScript面试题及详细答案100道(51-60)
7TypeScript面试题及详细答案100道(61-70)
8TypeScript面试题及详细答案100道(71-80)
9TypeScript面试题及详细答案100道(81-90)
10TypeScript面试题及详细答案100道(91-100)
http://www.dtcms.com/a/515464.html

相关文章:

  • 全球外贸网站制作教程icp网站快速备案
  • 《Hiding Images in Diffusion Models by Editing Learned Score Functions》 论文阅读
  • 频率分集阵列雷达——论文阅读
  • 网站备案信息如何下载潍坊市住房和城乡建设局网站下载
  • 比较好的企业网站百度举报网站
  • 数据库加密技术
  • nginx配置内嵌网页
  • 【微服务】SpringBoot 整合轻量级安全框架JWE 项目实战详解
  • 一个完整的AI项目从需求分析到部署的全流程详解
  • UE5 材质-14:减法subtract节点适用于向量与标量,数学 if 组件,由已遮罩材质结合自发光参数,周期性改变蒙版的大小,实现溶解效果
  • 构建AI智能体:七十一、模型评估指南:准确率、精确率、F1分数与ROC/AUC的深度解析
  • 基于脚手架微服务的视频点播系统-客户端业务逻辑处理部分(二)
  • 电商网站开发 文献综述百度网址大全 旧版本
  • 网站平台建设保密协议新网域名续费
  • 机器学习之生成对抗网络(GAN)
  • 零基础-动手学深度学习-13.11. 全卷积网络
  • JMeter测试关系数据库: JDBC连接
  • Linux(五):进程优先级
  • 【算法专题训练】26、队列的应用-广度优先搜索
  • 可靠性SLA:服务稳定性的量化承诺
  • 收集飞花令碎片——C语言内存函数
  • c语言-字符串
  • 红帽Linux -章8 监控与管理进程
  • 企业网站规范简述seo的优化流程
  • LLaMA Factory进行微调训练的时候,有哪些已经注册的数据集呢?
  • 【人工智能系列:走近人工智能03】概念篇:人工智能中的数据、模型与算法
  • 江苏品牌网站设计如何做旅游休闲网站
  • 个人Z-Library镜像技术实现:从爬虫到部署
  • MySQL 索引深度指南:原理 · 实践 · 运维(适配 MySQL 8.4 LTS)
  • SVG修饰属性