TypeScript 面试题及详细答案 100题 (81-90)-- 类型守卫与类型收窄
·
《前后端面试题》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,SQL,Linux… 。

文章目录
- 一、本文面试题目录
- 81. 什么是类型守卫(Type Guard)?它的核心作用是什么?
- 82. `typeof`类型守卫的局限性是什么?它能识别哪些类型?
- 83. `instanceof`类型守卫的作用是什么?它适用于哪些场景?
- 84. 如何自定义类型守卫函数?语法是什么?举例说明。
- 85. `in`操作符如何作为类型守卫使用?举例说明。
- 86. 什么是“discriminated union”(可区分联合)?如何用它实现自动类型收窄?
- 87. `is`关键字在类型守卫中的作用是什么?
- 88. 如何用类型守卫处理联合类型中的`null`或`undefined`?
- 89. 什么是“断言函数”(Assertion Functions)?如何定义?与类型守卫的区别?
- 90. 类型收窄的“控制流分析”指什么?TypeScript如何根据条件语句收窄类型?
- 二、100道TypeScript面试题目录列表
一、本文面试题目录
81. 什么是类型守卫(Type Guard)?它的核心作用是什么?
- 原理说明:类型守卫(Type Guard)是TypeScript中一种特殊的表达式,用于在特定作用域内缩小变量的类型范围(即类型收窄)。它通过特定语法或逻辑判断,让TypeScript编译器能够确定变量的具体类型,从而避免类型错误。
- 核心作用:在联合类型等场景中,明确变量的具体类型,使开发者可以安全地访问该类型特有的属性或方法,无需额外的类型断言。
- 示例代码:
type StringOrNumber = string | number; function isString(value: StringOrNumber): value is string { return typeof value === 'string'; } function logValue(value: StringOrNumber) { if (isString(value)) { // 类型收窄为string,可安全调用string方法 console.log(value.toUpperCase()); } else { // 类型收窄为number,可安全调用number方法 console.log(value.toFixed(2)); } }
82. typeof类型守卫的局限性是什么?它能识别哪些类型?
- 原理说明:
typeof类型守卫通过typeof 变量的结果判断变量类型,是TypeScript内置的基础类型守卫。 - 可识别的类型:仅能准确识别
string、number、boolean、symbol、bigint、function、undefined这7种类型。 - 局限性:
- 无法区分
null和object(typeof null返回"object")。 - 无法识别具体的对象类型(如
Array、Date等,typeof []返回"object")。 - 对自定义类型(如类实例)无能为力。
- 无法区分
- 示例代码:
function checkType(value: any) { if (typeof value === 'string') { console.log('是字符串'); // 正确识别 } else if (typeof value === 'number') { console.log('是数字'); // 正确识别 } else if (typeof value === 'object') { // 无法区分null、数组、普通对象等 console.log('可能是对象、数组或null'); } }
83. instanceof类型守卫的作用是什么?它适用于哪些场景?
- 原理说明:
instanceof类型守卫通过判断对象是否为某个构造函数的实例(即是否由该构造函数创建),来收窄变量类型。它基于原型链的继承关系工作。 - 适用场景:
- 区分不同类的实例(如
Date、Array或自定义类)。 - 处理基于类的继承体系中的类型判断。
- 区分不同类的实例(如
- 示例代码:
class Dog { bark() { console.log('汪汪'); } } class Cat { meow() { console.log('喵喵'); } } function animalSound(animal: Dog | Cat) { if (animal instanceof Dog) { animal.bark(); // 类型收窄为Dog } else { animal.meow(); // 类型收窄为Cat } } // 对内置对象的判断 function handleValue(value: Date | Array<any>) { if (value instanceof Date) { console.log(value.toISOString()); // 类型收窄为Date } else { console.log(value.length); // 类型收窄为Array } }
84. 如何自定义类型守卫函数?语法是什么?举例说明。
- 原理说明:自定义类型守卫函数是开发者手动定义的函数,返回值类型为“
参数 is 目标类型”的布尔值,用于告诉TypeScript如何收窄变量类型。 - 语法:
function 函数名(参数: 联合类型): 参数 is 目标类型 { ... } - 示例代码:
type Fish = { swim: () => void }; type Bird = { fly: () => void }; // 自定义类型守卫:判断是否为Fish function isFish(animal: Fish | Bird): animal is Fish { return 'swim' in animal; // 通过是否有swim属性判断 } function move(animal: Fish | Bird) { if (isFish(animal)) { animal.swim(); // 类型收窄为Fish } else { animal.fly(); // 类型收窄为Bird } } // 更复杂的判断逻辑 type User = { role: 'user'; name: string }; type Admin = { role: 'admin'; id: number }; function isAdmin(person: User | Admin): person is Admin { return person.role === 'admin'; }
85. in操作符如何作为类型守卫使用?举例说明。
- 原理说明:
in操作符用于检查对象是否包含某个属性(属性名 in 对象),TypeScript会根据该判断自动收窄变量类型,因此可作为类型守卫使用。 - 适用场景:区分具有不同属性的联合类型成员。
- 示例代码:
type Car = { drive: () => void }; type Boat = { sail: () => void }; function moveVehicle(vehicle: Car | Boat) { if ('drive' in vehicle) { // 存在drive属性,类型收窄为Car vehicle.drive(); } else { // 不存在drive属性,类型收窄为Boat vehicle.sail(); } } // 处理可选属性 type WithName = { name?: string }; type WithoutName = {}; function checkName(obj: WithName | WithoutName) { if ('name' in obj) { // 类型收窄为WithName,可安全访问name(可能为undefined) console.log(obj.name?.toUpperCase()); } }
86. 什么是“discriminated union”(可区分联合)?如何用它实现自动类型收窄?
- 原理说明:可区分联合(discriminated union)是一种特殊的联合类型,其成员包含一个共同的“区分属性”(通常是字面量类型),TypeScript可通过该属性自动收窄类型,无需额外类型守卫。
- 实现条件:
- 联合类型的每个成员都有一个相同的属性(如
type)。 - 该属性的值为字面量类型(如字符串、数字),且各成员的值不同。
- 联合类型的每个成员都有一个相同的属性(如
- 示例代码:
// 定义可区分联合 type Circle = { kind: 'circle'; radius: number }; type Square = { kind: 'square'; sideLength: number }; type Triangle = { kind: 'triangle'; base: number; height: number }; type Shape = Circle | Square | Triangle; // 自动类型收窄 function getArea(shape: Shape): number { switch (shape.kind) { case 'circle': // 自动收窄为Circle,可访问radius return Math.PI * shape.radius **2; case 'square': // 自动收窄为Square,可访问sideLength return shape.sideLength** 2; case 'triangle': // 自动收窄为Triangle,可访问base和height return (shape.base * shape.height) / 2; } }
87. is关键字在类型守卫中的作用是什么?
- 原理说明:
is关键字是自定义类型守卫函数的核心,用于声明“当函数返回true时,参数的类型为is右侧指定的类型”。它建立了函数返回值与参数类型之间的关联,让TypeScript能够根据函数的返回结果收窄参数类型。 - 作用:
- 明确告诉编译器类型判断逻辑,实现自定义的类型收窄规则。
- 使类型守卫函数的返回值具备“类型断言”的效果,替代手动的
as断言。
- 示例代码:
type A = { a: number }; type B = { b: string }; // 没有is关键字:仅返回布尔值,无法收窄类型 function hasA(obj: A | B): boolean { return 'a' in obj; } // 有is关键字:返回值关联类型,可收窄类型 function isA(obj: A | B): obj is A { return 'a' in obj; } function handle(obj: A | B) { if (hasA(obj)) { // 错误:TypeScript无法确定obj是A // console.log(obj.a); } if (isA(obj)) { // 正确:类型收窄为A console.log(obj.a); } }
88. 如何用类型守卫处理联合类型中的null或undefined?
- 原理说明:
null和undefined常作为联合类型的成员(如string | null),类型守卫可通过判断排除这两种类型,收窄为有效类型。 - 常见方式:
- 使用
!== null或!== undefined直接判断。 - 使用
typeof(typeof value !== 'undefined')。 - 自定义类型守卫函数(如
isNotNull)。
- 使用
- 示例代码:
type MaybeString = string | null | undefined; // 方式1:直接判断排除null/undefined function logIfValid(value: MaybeString) { if (value !== null && value !== undefined) { console.log(value.toUpperCase()); // 类型收窄为string } } // 方式2:自定义类型守卫 function isNotNullish<T>(value: T | null | undefined): value is T { return value !== null && value !== undefined; } function process(value: MaybeString) { if (isNotNullish(value)) { console.log(value.length); // 类型收窄为string } else { console.log('值为null或undefined'); } }
89. 什么是“断言函数”(Assertion Functions)?如何定义?与类型守卫的区别?
- 原理说明:断言函数(Assertion Functions)是一种特殊函数,用于强制断言参数的类型,如果断言失败会抛出错误。它的作用是“确保参数一定是某个类型”,而非“判断参数可能是某个类型”。
- 定义语法:返回值类型为
asserts 参数 is 目标类型。 - 与类型守卫的区别:
特性 类型守卫函数 断言函数 返回值 boolean无(或抛出错误) 作用 可能为目标类型(条件判断) 必须为目标类型(强制断言) 失败处理 不抛出错误,走else逻辑 必须抛出错误 - 示例代码:
type PositiveNumber = number; // 断言函数:确保参数是正数,否则抛出错误 function assertPositive(n: number): asserts n is PositiveNumber { if (n <= 0) { throw new Error('必须是正数'); } } function calculate(n: number) { assertPositive(n); // 断言成功后,n的类型收窄为PositiveNumber console.log('平方根:', Math.sqrt(n)); } calculate(4); // 正常执行 calculate(-1); // 抛出错误
90. 类型收窄的“控制流分析”指什么?TypeScript如何根据条件语句收窄类型?
- 原理说明:控制流分析(Control Flow Analysis)是TypeScript编译器跟踪变量在不同代码分支(如
if、else、switch、循环等)中的类型变化,并自动收窄类型的过程。它模拟代码的执行路径,推断变量在特定分支中的具体类型。 - TypeScript的收窄方式:
- 条件判断:通过
if (condition)中的条件(如typeof、instanceof、in等)收窄类型。 - 逻辑运算符:
&&、||、!等逻辑判断影响类型(如if (!value)排除null/undefined)。 - switch语句:根据
case分支的判断收窄类型(尤其适用于可区分联合)。 - throw/return:在分支中抛出错误或返回时,后续代码的类型会相应收窄。
- 条件判断:通过
- 示例代码:
type Value = string | number | null; function processValue(v: Value) { if (v === null) { console.log('值为null'); return; // 此处返回后,后续代码中v不可能为null } // 控制流分析:v的类型收窄为string | number if (typeof v === 'string') { // 收窄为string console.log(v.length); } else { // 收窄为number console.log(v.toFixed(1)); } } // switch语句中的控制流分析 type Fruit = 'apple' | 'banana' | 'orange'; function getColor(f: Fruit) { switch (f) { case 'apple': return 'red'; case 'banana': return 'yellow'; // case 'orange': 若注释此行,TypeScript会提示缺少分支 default: const _exhaustiveCheck: never = f; return _exhaustiveCheck; } }
二、100道TypeScript面试题目录列表
更多推荐


所有评论(0)