2023-06-22 12:37:30
在 TypeScript 中,判断类型需要结合多种方法,因为简单的 typeof 操作符无法满足复杂类型的需求。以下是详细的类型判断方法:
typeof 操作符:适用于基础类型,如 number、string、boolean、symbol、bigint 和 undefined。但对于对象类型,它只能返回 object,无法区分具体类型。
instanceof 操作符:用于检查一个对象是否为特定类的实例。例如:
class MyClass {}const obj = new MyClass();if (obj instanceof MyClass) { // obj 被识别为 MyClass 类型}类型守卫:通过自定义函数缩小变量的类型范围。例侍册余如:
function isStringArray(arr: any): arr is string[] { return Array.isArray(arr) && arr.every(item => typeof item === 'string');}let myArray: any = ['apple', 'banana', 'cherry'];if (isStringArray(myArray)) { // myArray 被识别为 string[] 类型 console.log(myArray.join(', '));}类型断言:告诉编译器你确信变量的类型,但需谨慎使用,因为错误的断言可能导致运行时错误。例如:
interface Person { name: string; age: number;}let data: any = { name: 'John Doe', age: 30 };let person: Person = data as Person; // 类型断言console.log(person.name);用姿举户老滚定义的类型守卫:通过返回类型谓词(如 param is Type)来缩小类型范围。例如:
function isPerson(obj: any): obj is Person { return obj && obj.name && typeof obj.name === 'string' && obj.age && typeof obj.age === 'number';}in 操作符:检查对象是否包含某个属性,常用于区分不同接口的对象。例如:
interface A { a: number; }interface B { b: string; }function checkType(obj: A | B) { if ('a' in obj) { // obj 被识别为 A 类型 } else { // obj 被识别为 B 类型 }}可辨识联合:通过共同属性区分不同类型。例如:
type Circle = { kind: 'circle'; radius: number };type Square = { kind: 'square'; side: number };type Shape = Circle | Square;function getArea(shape: Shape) { switch (shape.kind) { case 'circle': return Math.PI * shape.radius 2; case 'square': return shape.side 2; }}类型谓词:在函数中返回类型谓词,帮助编译器推断类型。例如:
function isNumber(value: any): value is number { return typeof value === 'number';}运行时类型检查:使用第三方库如 io-ts 或 zod 进行复杂的运行时类型验证。例如:
import * as t from 'io-ts';const Person = t.type({ name: t.string, age: t.number });const data = { name: 'John', age: 30 };if (Person.is(data)) { // data 被识别为 Person 类型}泛型与类型约束:通过泛型参数和 extends 关键字约束类型。例如:
function logLength<T extends { length: number }>(arg: T) { console.log(arg.length);}映射类型与条件类型:利用高级类型工具进行类型判断和转换。例如:
type IsString<T> = T extends string ? true : false;type A = IsString<'hello'>; // truetype B = IsString<123>; // false自定义类型保护类:通过类方法实现类型保护。例如:
class TypeChecker { static isString(value: any): value is string { return typeof value === 'string'; }}使用 unknown 替代 any:unknown 类型更安全,需要显式类型检查后才能使用。例如:
let value: unknown = 'hello';if (typeof value === 'string') { console.log(value.toUpperCase());}类型缩小策略:结合控制流分析缩小类型范围。例如:
function processInput(input: string | number) { if (typeof input === 'string') { console.log(input.trim()); } else { console.log(input.toFixed(2)); }}高级模式匹配:使用解构和默认值进行类型推断。例如:
function greet({ name = 'Guest' }: { name?: string }) { console.log(`Hello, ${name}!`);}类型兼容性检查:利用 = 和 extends 进行类型兼容性判断。例如:
type T1 = { a: number };type T2 = { a: number; b: string };type Check = T2 extends T1 ? true : false; // true使用 satisfies 操作符(TypeScript 4.9+):验证值是否符合类型而不改变其类型。例如:
type Colors = 'red' | 'green' | 'blue';const favorite = 'red' satisfies Colors; // 验证 'red' 是 Colors 类型类型查询与 keyof:动态获取和检查类型。例如:
interface User { id: number; name: string;}type UserKeys = keyof User; // 'id' | 'name'模板字面量类型:用于字符串类型的精确判断。例如:
type EventName = `click${string}`;function handleEvent(name: EventName) {}handleEvent('clickSave'); // 有效handleEvent('save'); // 错误使用 asserts 关键字:定义断言函数。例如:
function assertIsString(value: any): asserts value is string { if (typeof value !== 'string') throw new Error('Not a string');}类型推断与泛型默认值:结合泛型和默认值进行类型判断。例如:
function createContainer<T = string>() { return { value: '' as T };}使用 Exclude 和 Extract:从联合类型中排除或提取特定类型。例如:
type T = Exclude<'a' | 'b' | 'c', 'a'>; // 'b' | 'c'类型映射与 Record:动态生成和检查对象类型。例如:
type UserMap = Record<string, User>;const users: UserMap = { user1: { id: 1, name: 'Alice' } };使用 NonNullable:排除 null 和 undefined。例如:
type T = NonNullable<string | null | undefined>; // string类型守卫库:使用如 ts-guard 等库简化类型守卫的创建。例如:
import { guard } from 'ts-guard';const isUser = guard<User>({ id: 'number', name: 'string' });运行时类型生成:通过代码生成工具创建类型守卫。例如:
// 使用工具生成类型检查代码类型反射与元编程:利用高级特性进行类型判断(实验性)。例如:
// 使用装饰器或反射 API(需额外配置)类型检查的边界情况:注意类型判断的局限性,