TypeScript 类型缩小的几种实现方式

作者:小括号

时间:2026-10-31

浏览:103

本文深入解析 TypeScript 中的类型缩小机制,涵盖 instanceof、typeof、相等性检查、真值判断及类型谓词五种核心方式。通过具体代码示例,展示如何在不同场景下利用类型保护细化变量类型,提升代码的安全性与可维护性。

文章目录

TypeScript 类型缩小(Narrowing)依据特定条件将变量类型细化为更具体类型的过程,旨在提升代码精确度与准确性,确保变量在运行时严格遵循其类型约束。

一、instanceof缩小类型

TypeScript 中的 instanceof 运算符用于执行类型缩小,通过验证对象是否属于特定类或构造函数实例来实现。在条件语句中应用 instanceof 时,TypeScript 会依据验证结果自动缩小变量类型。

(一) 语法

if (objectToCheck instanceof ConstructorFunction) {
  // 如果 objectToCheck 是 ConstructorFunction 的实例,则执行此代码块
}

关键参数说明如下:

  • objectToCheck:待检测的目标对象,用于判定其是否为特定类或构造函数的实例。
  • ConstructorFunction:用于检测的构造函数或类。若 objectToCheck 为其实例,条件为 true,TypeScript 将相应缩小 objectToCheck 的类型。
  • instanceof:用于类型缩小的关键字,用于判断对象是否属于特定类或构造函数实例。

(二) 用法举例

1. 例一

示例包含 Car 和 Bicycle 两个类,分别具备 start 和 pedal 方法。startVehicle 函数接收 vehicle 参数,类型可为 Car 或 Bicycle。函数内部利用 instanceof 检测 vehicle 类型:若为 Car 实例,类型缩小为 Car,可调用 start 方法;若为 Bicycle 实例,类型缩小为 Bicycle,可调用 pedal 方法。

class Car {
  start() {
    console.log("Car started");
  }
}
class Bicycle {
  pedal() {
    console.log("Bicycle pedaling");
  }
}
function startVehicle(vehicle: Car | Bicycle) {
  if (vehicle instanceof Car) {
    // 在此代码块中,'vehicle' 的类型被缩小为 'Car'
    vehicle.start();
  } else {
    // 在此代码块中,'vehicle' 的类型被缩小为 'Bicycle'
    vehicle.pedal();
  }
}
const myCar = new Car();
const myBicycle = new Bicycle();
startVehicle(myCar);
startVehicle(myBicycle);

输出:

一、instanceof缩小类型

2. 例二

示例展示 Animal、Dog 和 Cat 的继承关系。animalSound 函数接收 Animal 类型参数,内部使用 instanceof 检测 animal 是否为 Dog 或 Cat 实例。若为 Dog,类型缩小为 Dog,调用 speak 方法发出狗叫;若为 Cat,类型缩小为 Cat,调用 speak 方法发出猫叫;否则保持 Animal 类型,调用通用 speak 方法。

class Animal {
  speak() {
    console.log("Animal makes a sound");
  }
}
class Dog extends Animal {
  speak() {
    console.log("Dog barks");
  }
}
class Cat extends Animal {
  speak() {
    console.log("Cat meows");
  }
}
function animalSound(animal: Animal) {
  if (animal instanceof Dog) {
    // 在此代码块中,'animal' 的类型被缩小为 'Dog'
    animal.speak(); // 调用 Dog 的 speak 方法
  } else if (animal instanceof Cat) {
    // 在此代码块中,'animal' 的类型被缩小为 'Cat'
    animal.speak(); // 调用 Cat 的 speak 方法
  } else {
    // 在此代码块中,'animal' 仍然是 'Animal' 类型
    animal.speak(); // 调用 Animal 的 speak 方法
  }
}
const dog = new Dog();
const cat = new Cat();
const genericAnimal = new Animal();
animalSound(dog);
animalSound(cat);
animalSound(genericAnimal);

输出:

一、instanceof缩小类型

二、typeof类型保护

本节探讨 typeof 类型保护(type guards)中的类型缩小机制。TypeScript 作为构建可扩展且健壮应用的主流语言,其 typeof 类型保护允许依据 typeof 运算符的结果缩小变量类型。

该机制在处理 string、number、boolean、symbol 和 undefined 等原始类型时尤为实用,亦可用于检测变量是否为函数(function)或对象(object)。

以下是 typeof 运算符可识别的类型列表:

  • string
  • number
  • bigint
  • boolean
  • symbol
  • undefined
  • object
  • function

(一) 语法

if (typeof variable === 'type') {
  // 当变量匹配指定类型时执行的代码
}

参数定义如下:

  • typeof:TypeScript 中用于检测变量类型的运算符。
  • variable:待检测类型的目标变量。
  • 'type':表示期望检测类型的字符串字面量。

(二) 用法举例

1. 例一

利用 typeof 检测变量是否属于字符串类型。

const p = '2025 TypeScript Learning Guide';
if (typeof p === 'string') {
  // 在这里,TypeScript 知道 'p' 是一个字符串。
  console.log(p.toUpperCase());
}

输出:2025 TYPESCRIPT LEARNING GUIDE

2. 例二

利用 typeof 检测变量是否属于数字类型。

const age = 30;
if (typeof age === 'number') {
  // TypeScript 知道 'age' 是一个数字。
  console.log(age * 2);
}

输出:60

3. 例三

利用 typeof 检测变量是否属于布尔类型(boolean)。

const isActive = true;
if (typeof isActive === 'boolean') {
  // TypeScript 知道 'isActive' 是一个布尔值。
  console.log(isActive);
}

输出:false

4. 例四

利用 typeof 检测变量是否属于符号类型(symbol)。

const uniqueSymbol = Symbol('unique');
if (typeof uniqueSymbol === 'symbol') {
  // TypeScript 知道 'uniqueSymbol' 是 symbol 类型。
  console.log(uniqueSymbol.description);
}

输出:unique

5. 例五

利用 typeof 检测变量是否属于 undefined 类型。

let someValue;
if (typeof someValue === 'undefined') {
  // TypeScript 知道 
  // 'someValue' 是 undefined 类型。
  console.log('值是未定义的。');
}

输出:值是未定义的。

6. 例六

此示例检测变量类型是否为对象(typeof 为 "object"),但无法区分具体对象类型,仅能排除其他基本类型。需结合 instanceof 或检查特定属性以实现更精确的类型判断。

const person = {
  name: 'FelixLu',
  age: 30,
};
if (typeof person === 'object') {
  console.log('person 是一个对象');
  // 在这个代码块内,你可以安全地访问 person 的属性
  console.log(`名字: ${person.name}, 年龄: ${person.age}`);
}

输出:

person 是一个对象 名字: FelixLu, 年龄: 30

7. 例七

利用 typeof 检测变量是否属于函数类型。

function greet() {
  console.log('Hello!');
}
if (typeof greet === 'function') {
  // TypeScript 知道 'greet' 是一个函数。
  greet();
}

输出:Hello!

三、相等缩小类型

本节介绍 TypeScript 中的“相等缩小类型”(Equality Narrowing Type)。

(一) 语法

TypeScript 作为构建可扩展且健壮应用的主流语言,“相等缩小”指依据相等性检查或比较来缩小变量类型的过程。TypeScript 通过相等性检查符号(===、==、!==、!=)或比较运算符(<、>、<=、>=)推断更具体类型,亦可利用 switch 语句实现类型缩小。

JavaScript 中较宽松的相等检查(== 和 !=)同样能被 TypeScript 正确缩小类型。例如,检查值是否 == null 不仅判断是否为 null,还涵盖是否为 undefined;同理,== undefined 检查涵盖值为 null 或 undefined 的情况。

(二) 用法举例

1. 例一

示例中 processValue 函数接收 number | string 类型的 value 参数。函数内部使用 typeof value === 'number' 检测 value 是否为数字类型:若是,TypeScript 在 if 代码块内将 value 类型缩小为 number,可安全执行数值操作;若否,TypeScript 在 else 代码块中将 value 类型缩小为 string,可安全调用 toUpperCase() 方法。

function processValue(value: number | string): void {
  if (typeof value === 'number') {
    // 在这个代码块中,TypeScript
    // 将 value 的类型缩小为 'number'
    // 它知道 value 是数字类型
    console.log(value + 10);
  } else {
    // 在这个代码块中,TypeScript
    // 将 value 的类型缩小为 'string'
    // 它知道 value 是字符串类型
    console.log(value.toUpperCase());
  }
}
// 使用示例:
processValue(5);
processValue('TypeScript');

输出:

一、instanceof缩小类型

2. 例二

示例定义 processArray 函数,接收 number[] 或 string[] 类型的 arr 参数。函数内部通过 Array.isArray(arr) 检测 arr 是否为数组:若是,TypeScript 在 if 代码块中将 arr 类型缩小为 number[] 或 string[]。

在 forEach 循环中,TypeScript 进一步根据数组元素类型缩小 item 类型:若 item 为数字,识别为数字类型;若为字符串,识别为字符串类型。这使得在循环内可安全执行针对数字或字符串的特定操作,避免类型错误。

使用 numberArray 和 stringArray 调用 processArray 时,TypeScript 正确缩小类型,并在函数内执行类型安全操作。

function processArray(arr: number[] | string[]): void {
  if (Array.isArray(arr)) {
    // TypeScript 在此代码块中将 arr 的类型缩小为
    // 'number[]' 或 'string[]'
    arr.forEach((item) => {
      if (typeof item === "number") {
        // TypeScript 在这里将 item 的类型缩小为 'number'
        console.log(`Number: ${item}`);
      } else {
        // TypeScript 在这里将 item 的类型缩小为 'string'
        console.log(`String: ${item}`);
      }
    });
  }
}
const numberArray: number[] = [1, 2, 3];
const stringArray: string[] = ["Typescript", "Java", "React"];
processArray(numberArray);
processArray(stringArray);

输出:

一、instanceof缩小类型

3. 例三

示例中 printPersonInfo 函数接收 Person 类型参数 person。Person 接口包含 name 属性和可选的 age 属性。函数内部使用 in 操作符检测 person 对象是否存在 age 属性:若存在('age' in person 为 true),TypeScript 在 if 代码块中缩小 person 类型,使其包含 age 属性,可安全访问 person.age;若不存在('age' in person 为 false),TypeScript 在 else 代码块中缩小类型,排除 age 属性。

interface Person {
  name: string;
  age?: number;
}
function printPersonInfo(person: Person) {
  if ('age' in person) {
    // 在此代码块中,'person' 被缩小为包含 'age' 属性的类型
    console.log(`Name: ${person.name}, Age: ${person.age}`);
  } else {
    // 在此代码块中,'person' 被缩小为不包含 'age' 属性的类型
    console.log(`Name: ${person.name}, Age not provided`);
  }
}
const p1: Person = { name: 'FelixLu', age: 30 };
const p2: Person = { name: 'Felix' };
printPersonInfo(p1);
printPersonInfo(p2);

输出:

一、instanceof缩小类型

四、真值收窄类型

本节学习 TypeScript 中的真值收窄类型(Truthiness Narrowing Type)。

TypeScript 作为构建可扩展且健壮应用的主流语言,“真值收窄”是一种依据变量在条件语句中真假值来缩小其类型的机制。该类型推断机制利用 JavaScript 中的“真值”(truthy)和“假值”(falsy)确定变量可能类型。

真值(Truthy Values):

在 JavaScript 中,被视为“真值”的值在布尔上下文中按 true 处理,包括:

  • 非空字符串(如 "hello"、"true" 等)
  • 非零数字(如 1、-42 等)
  • 对象(包括数组和函数)
  • true
  • 拥有 valueOf 方法并返回 true 的用户自定义类的实例

假值(Falsy Values):

相反,被视为“假值”的值在布尔上下文中按 false 处理,包括:

  • 空字符串("")
  • 数字 0(0)
  • null
  • undefined
  • false
  • 0n(BigInt 类型的零)
  • NaN(不是一个数字)

(一) 语法

if (condition) {
  // 在这个代码块中,TypeScript 会收窄变量的类型。
} else {
  // 在这个代码块中,TypeScript 会根据条件得知变量的不同类型信息。
}

参数说明如下:

  • condition:待检测“真值”或“假值”的表达式或变量。
  • if 代码块中:TypeScript 依据条件真值情况收窄变量类型。若条件为 true,TypeScript 相应收窄变量类型。
  • else 代码块中(可选):因条件判定为 false,TypeScript 对变量进行与 if 块相反的类型推断。

(二) 用法举例

1. 例一

在 if 代码块中,TypeScript 将 name 类型收窄为 string,因其检测 name 是否为真值(即非 null 或 undefined)。在 else 代码块中,TypeScript 理解 name 仅能是 null 或 undefined,因已在 if 中检测其为真值。

function greet(name: string | null) {
  if (name) {
    // 在这个代码块中,TypeScript 知道 
    // 'name' 是一个非 null 的字符串。
    console.log(`Hello, ${name.toUpperCase()}!`);
  } else {
    // 在这个代码块中,TypeScript 知道 
    // 'name' 要么是 null,要么是 undefined。
    console.log("Hello, TypeScript!");
  }
}
greet("TypeScript");
greet(null);

输出:

一、instanceof缩小类型

2. 例二

示例中 printType 函数接收参数 value。函数内部使用 typeof 检测 value 类型。依据不同类别,TypeScript 在每个 if 代码块中收窄 value 类型,从而安全执行与类型相关的操作。

function printType(value: any) {
  if (typeof value === 'string') {
    console.log("它是一个字符串:", value.toUpperCase());
  } else if (typeof value === 'number') {
    console.log("它是一个数字:", value.toFixed(2));
  } else {
    console.log("它是其他类型:", value);
  }
}
printType("Hello, TypeScript!");
printType(42);
printType(true);

输出:

一、instanceof缩小类型

五、类型谓词

本文学习 TypeScript 中的类型谓词。TypeScript 作为静态类型编程语言,提供诸多功能以提升代码效率与健壮性。类型谓词为返回布尔值的函数,用于缩小变量类型范围,主要应用于条件语句块中检测变量是否属于特定类型并执行相应操作。类型谓词可使用 TypeScript 关键字 “is” 定义。

(一) 语法

function is<TypeName>(variable: any): variable is TypeName {
  // 返回布尔值
}

语法中,TypeName 为待检测的类型名称,variable 为待缩小类型范围的变量。is 关键字表示函数返回布尔值,variable is TypeName 告知 TypeScript,若函数返回 true,则变量为指定类型。

(二) 用法举例

1. 使用原始类型的类型谓词

示例展示类型谓词与原始类型的协作。假设函数接收类型为 any 的变量,欲检测其是否为字符串,可定义如下类型谓词函数:利用 JavaScript 中的 typeof 操作符判断变量是否为字符串。若为字符串,函数返回 true;否则返回 false。

随后在条件语句中调用 isString 函数检测变量是否为字符串,并打印选定结果。

let variable: any = 'hello';
if (isString(variable)) {
  console.log("给定的变量是字符串类型");
}
function isString(variable: any): variable is string {
  return typeof variable === 'string';
}

输出:

一、instanceof缩小类型

2. 带自定义类型的类型谓词

另一示例展示类型谓词与自定义类型的协作。假设存在表示“Person”对象的接口,定义类型谓函数检测变量是否为“Person”类型。函数利用 in 操作符检测变量是否包含 name、age 和 address 属性。若为“Person”类型,函数返回 true;否则返回 false。随后在条件语句中调用此类型谓函数,若返回 true,即可安全访问“address”对象中的 city 属性,因此时已知变量类型为“Person”。

interface Person {
  name: string;
  age: number;
  address: {
    street: string;
    city: string;
    zip: number;
  };
}
// 定义类型谓词函数,判断变量是否为 Person 类型
function isPerson(variable: any): variable is Person {
  return (
    typeof variable === "object" && // 判断变量是对象
    variable !== null &&             // 且不为 null
    "name" in variable &&            // 并且拥有 name 属性
    "age" in variable &&             // 拥有 age 属性
    "address" in variable            // 拥有 address 属性
  );
}
let variable: any = {
  name: "John",
  age: 30,
  address: {
    street: "皂君庙甲10号",
    city: "北京",
    zip: 10001
  },
};
// 如果变量是 Person 类型,则安全访问 address.city 属性
if (isPerson(variable)) {
  console.log(variable.address.city);
}

输出:

一、instanceof缩小类型

到此这篇关于TypeScript 类型缩小的几种实现方式的文章就介绍到这了,更多相关TypeScript 类型缩小内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章