TypeScript进阶(三)类型演算与高级内置类型

简介: TypeScript 是一种静态类型检查的 JavaScript 超集,它通过类型注解和类型推断来提供更强大的类型系统。在 TypeScript 中,类型演算是一种重要的概念,它允许我们在编译时对类型进行操作和计算。本文将深入探讨 TypeScript 类型演算的原理和应用。

引言

TypeScript 是一种静态类型检查的 JavaScript 超集,它通过类型注解和类型推断来提供更强大的类型系统。在 TypeScript 中,类型演算是一种重要的概念,它允许我们在编译时对类型进行操作和计算。本文将深入探讨 TypeScript 类型演算的原理和应用。


基本概念

在 TypeScript 中,类型是一种值的属性。通过将值与其对应的类型进行关联,我们可以在编译时检查代码中的类型错误。而类型演算则是对这些类型进行操作和计算的过程。

TypeScript 提供了一系列内置的操作符和关键字来进行类型演算。例如,typeof 操作符可以用于获取一个值的类型;keyof关键字可以用于获取一个对象所有属性名组成的联合类型;in 关键字可以用于遍历一个联合类型中所有成员等等。

类型推断与上下文

在 TypeScript 中,编译器会根据上下文自动推断变量或表达式的类型。这种基于上下文的推断机制使得代码更加简洁且易读。

例如,在以下代码中:

letx=10;

编译器会自动推断变量 x 的类型为 number。这是因为赋给 x 的值是一个数字字面量。

类型操作符

TypeScript 提供了一系列类型操作符,用于对类型进行操作和计算。这些操作符包括联合类型(|)、交叉类型(&)、索引访问操作符([])、条件类型(extends ? :)等等。

例如,我们可以使用联合类型来定义一个变量可以接受多种不同类型的值:

letx: number|string;

这样,变量 x 可以接受 number 类型或 string 类型的值。

条件类型

条件类型是 TypeScript 中一种非常强大的类型演算工具。它允许我们根据某个条件来选择不同的类型。

例如,我们可以使用条件类型来实现一个根据输入参数的不同返回不同结果的函数:

typeResult<T>=Textendsnumber?string : boolean;
functiongetResult<T>(input: T): Result<T> {
if (typeofinput==="number") {
return"number";
  } else {
returntrue;
  }
}

在上述代码中,如果输入参数是一个数字,则返回字符串类型;否则返回布尔值。

映射类型

映射类型是 TypeScript 中一种非常有用的工具,它允许我们根据已有的对象定义新的对象类型。

例如,我们可以使用映射类型来将一个对象中所有属性都设置为只读:

typeReadonlyObject<T>= {
readonly [PinkeyofT]: T[P];
};
constobj: ReadonlyObject<{ name: string; age: number }>= {
name: "Alice",
age: 20,
};
obj.name="Bob"; // Error: Cannot assign to 'name' because it is a read-only property.

类型守卫

类型守卫是 TypeScript 中一种用于缩小类型范围的机制。通过使用类型守卫,我们可以在特定条件下判断一个值的类型,并在代码块中使用该类型。

例如,我们可以使用 typeof 操作符来判断一个值的类型,并在代码块中使用该类型:

functionprintValue(value: string|number) {
if (typeofvalue==="string") {
console.log(value.toUpperCase());
  } else {
console.log(value.toFixed(2));
  }
}

在上述代码中,如果 value 是一个字符串,则将其转换为大写字母并打印;否则将其保留两位小数并打印。

类型演算的应用

通过深入理解 TypeScript 类型演算,我们可以更好地利用 TypeScript 的强大类型系统来编写更安全、更健壮的代码。

例如,在开发过程中,我们经常需要对输入参数进行验证和处理。通过使用条件类型和映射类型等工具,我们可以根据输入参数的不同来选择不同的处理逻辑,并根据已有对象定义新的对象类型。

此外,在编写通用库或框架时,类型演算也是非常有用的。通过使用类型演算,我们可以实现更加灵活和可扩展的类型定义,从而提供更好的类型推断和代码提示。

操作符

当谈到 TypeScript 类型演算时,typeof、keyof 和 in 是三个非常重要的操作符和关键字。它们在类型系统中扮演着不同的角色,用于获取类型信息、操作对象属性和遍历联合类型成员。下面将详细讲解它们的作用及使用示例。

typeof 操作符

typeof 是一个在 JavaScript 中已经存在的操作符,用于获取一个值的类型。在 TypeScript 中,typeof 操作符也可以用于获取一个值的类型,并将其作为一个类型注解或类型声明使用。

letx=10;
lety: typeofx; // y 的类型为 number

在上述代码中,typeof x 返回 number 类型,并将其赋值给变量 y。

keyof 关键字

keyof 是 TypeScript 中的一个关键字,用于获取一个对象所有属性名组成的联合类型。通过 keyof 关键字,我们可以在编译时获取对象属性名,并将其作为一个类型注解或类型声明使用。

typePerson= {
name: string;
age: number;
};
typePersonKeys=keyofPerson; // PersonKeys 的类型为 "name" | "age"

在上述代码中,keyof Person 返回 "name" | "age" 类型,并将其赋值给 PersonKeys。

in 关键字

in 是 TypeScript 中的一个关键字,用于遍历一个联合类型中所有成员。通过 in 关键字,我们可以在编译时对联合类型进行遍历,并将其作为一个类型注解或类型声明使用。

typeFruit="apple"|"banana"|"orange";
typeFruitInfo= {
 [PinFruit]: number;
};
constfruitCount: FruitInfo= {
apple: 5,
banana: 3,
orange: 2,
};

在上述代码中,[P in Fruit] 表示遍历 Fruit 联合类型中的所有成员,并将其作为 FruitInfo 对象的属性名,属性值的类型为 number。

通过使用 typeof、keyof 和 in,我们可以在 TypeScript 中对类型进行操作和计算,从而实现更加灵活和可扩展的类型定义。这些操作符和关键字在实际开发中非常有用,可以帮助我们编写更安全、更健壮的代码,并提高开发效率。

内置类型

  • Omit<T, K>
  • Pick<T, K>
  • Record<K, T>
  • Partial<T>
  • Required<T>
  • Readonly<T>
  • Exclude<T, U>
  • Extract<T, U>
  • NonNullable<T>
  • ReturnType<T>
  • InstanceType<T>

Omit<T, K>

Omit 用于从类型 T 中排除指定属性 K。它会创建一个新的类型,其中排除了属性 K。

typePerson= {
name: string;
age: number;
address: string;
};
typePersonWithoutAddress=Omit<Person, 'address'>;
// PersonWithoutAddress 的类型为 { name: string; age: number; }

在上述代码中,Omit 从 Person 类型中排除了属性 'address'。

Pick<T, K>

用于从类型 T 中选择指定属性 K。它会创建一个新的类型,其中只包含属性 K。

typePerson= {
name: string;
age: number;
address: string;
};
typePersonNameAndAge=Pick<Person, 'name'|'age'>;
// PersonNameAndAge 的类型为 { name: string; age: number; }

在上述代码中,Pick 从 Person 类型中选择了属性 'name' 和 'age'。

Record<K, T>

用于创建一个新的对象类型,其中键为类型 K 中的值,值为类型 T。

typeFruit='apple'|'banana'|'orange';
typeFruitCount=Record<Fruit, number>;
// FruitCount 的类型为 { apple: number; banana: number; orange: number; }

在上述代码中,Record 创建了一个对象类型,其中键为 Fruit 类型中的值,值为 number 类型。

Partial<T>

用于将类型 T 中的所有属性变为可选属性。它会创建一个新的类型,其中所有属性都变为可选。

typePerson= {
name: string;
age: number;
};
typePartialPerson=Partial<Person>;
// PartialPerson 的类型为 { name?: string; age?: number; }

在上述代码中,Partial<Person> 将 Person 类型中的所有属性变为可选属性。

Required<T>

用于将类型 T 中的所有属性变为必选属性。它会创建一个新的类型,其中所有属性都变为必选。

typePartialPerson= {
name?: string;
age?: number;
};
typeRequiredPerson=Required<PartialPerson>;
// RequiredPerson 的类型为 { name: string; age: number; }

在上述代码中,Required<PartialPerson> 将 PartialPerson 类型中的所有属性变为必选属性。

Readonly<T>

用于将类型 T 中的所有属性变为只读属性。它会创建一个新的类型,其中所有属性都变为只读。

typePerson= {
name: string;
age: number;
};
typeReadonlyPerson=Readonly<Person>;
// ReadonlyPerson 的类型为 { readonly name: string; readonly age: number; }

在上述代码中,Readonly<Person> 将 Person 类型中的所有属性变为只读属性。

Exclude<T, U>

用于从类型 T 中排除类型 U。它会创建一个新的类型,其中排除了类型 U 的成员。

typeFruit="apple"|"banana"|"orange";
typeExcludeFruit=Exclude<Fruit, "banana">;
// ExcludeFruit 的类型为 "apple" | "orange"

在上述代码中,Exclude 从 Fruit 类型中排除了值为 "banana" 的成员。

Extract<T, U>

用于从类型 T 中提取出类型 U。它会创建一个新的类型,其中只包含类型 U 的成员。

typeFruit="apple"|"banana"|"orange";
typeExtractFruit=Extract<Fruit, "banana">;
// ExtractFruit 的类型为 "banana"

在上述代码中,Extract 从 Fruit 类型中提取出值为 "banana" 的成员。

NonNullable<T>

用于从类型 T 中排除 null 和 undefined。它会创建一个新的类型,其中不包含 null 和 undefined。

typeValue=string|null|undefined;
typeNonNullableValue=NonNullable<Value>;
// NonNullableValue 的类型为 string

在上述代码中,NonNullable<Value> 从 Value 类型中排除了 null 和 undefined。

ReturnType<T>

用于获取函数类型 T 的返回值类型。它会创建一个新的类型,其中只包含函数 T 的返回值类型。

typeMyFunction= () =>string;
typeMyFunctionReturnType=ReturnType<MyFunction>;
// MyFunctionReturnType 的类型为 string

在上述代码中,ReturnType<MyFunction> 获取了函数类型 MyFunction 的返回值类型。

InstanceType<T>

用于获取构造函数类型 T 的实例类型。它会创建一个新的类型,其中只包含构造函数 T 的实例类型。

classPerson {
name: string;
constructor(name: string) {
this.name=name;
  }
}
typePersonInstance=InstanceType<typeofPerson>;
// PersonInstance 的类型为 Person

在上述代码中,InstanceType<typeof Person> 获取了构造函数 Person 的实例类型。

Awaited<T>

用于获取 Promise 类型 T 的解析值类型。它会创建一个新的类型,其中包含了 Promise 类型 T 的解析值类型。

asyncfunctionfetchData(): Promise<string> {
return"Data";
}
typeAwaitedData=Awaited<ReturnType<typeoffetchData>>;
// AwaitedData 的类型为 string

在上述代码中,Awaited<ReturnType<typeof fetchData>> 获取了 fetchData 函数返回 Promise 的解析值类型。

Parameters<T>

用于获取函数类型 T 的参数类型组成的元组。它会创建一个新的类型,其中包含了函数 T 的参数类型组成的元组。

functiongreet(name: string, age: number): void {
console.log(`Hello, ${name}! You are ${age}years old.`);
}
typeGreetParams=Parameters<typeofgreet>;
// GreetParams 的类型为 [string, number]

在上述代码中,Parameters<typeof greet> 获取了 greet 函数的参数类型组成的元组。

通过这些 TypeScript 类型操作符,我们可以更灵活地操作和计算类型,并提供更强大的静态类型检查。这些操作符在实际开发中非常有用,可以帮助我们编写更安全、更健壮的代码,并提高开发效率。

总结

本文深入探讨了 TypeScript 类型演算的原理和应用。通过使用类型演算,我们可以在编译时对类型进行操作和计算,从而提供更强大的类型系统。通过合理地运用类型推断、条件类型、映射类型等工具,我们可以编写更安全、更健壮的代码,并提高开发效率。希望本文能够帮助读者深入理解 TypeScript 类型演算,并在实际开发中得到应用。

目录
相关文章
|
1天前
|
JavaScript 编译器
TypeScript中类型守卫:缩小类型范围的艺术
【4月更文挑战第23天】TypeScript中的类型守卫是缩小类型范围的关键技术,它帮助我们在运行时确保值的精确类型,提升代码健壮性和可读性。类型守卫包括`typeof`(检查原始类型)、`instanceof`(检查类实例)和自定义类型守卫。通过这些方法,我们可以更好地处理联合类型、泛型和不同数据源,降低运行时错误,提高代码质量。
|
1天前
|
JavaScript 前端开发 安全
Apollo与TypeScript:强大类型检查在前端开发中的应用
Apollo与TypeScript:强大类型检查在前端开发中的应用
|
1天前
|
监控 JavaScript 安全
TypeScript在员工上网行为监控中的类型安全实践
本文演示了如何使用TypeScript在员工上网行为监控系统中实现类型安全。通过定义`Website`类型和`MonitoringData`接口,确保数据准确性和可靠性。示例展示了从监控设备获取数据和提交到网站的函数,强调了类型定义在防止错误、提升代码可维护性方面的作用。
24 7
|
1天前
|
JavaScript 安全 前端开发
【TypeScript技术专栏】TypeScript中的类型推断与类型守卫
【4月更文挑战第30天】TypeScript的类型推断与类型守卫是提升代码安全的关键。类型推断自动识别变量类型,减少错误,包括基础、上下文、最佳通用和控制流类型推断。类型守卫则通过`typeof`、`instanceof`及自定义函数在运行时确认变量类型,确保类型安全。两者结合使用,优化开发体验,助力构建健壮应用。
|
1天前
|
JavaScript 前端开发 开发者
【TypeScript技术专栏】TypeScript类型系统与接口详解
【4月更文挑战第30天】TypeScript扩展JavaScript,引入静态类型检查以减少错误。其类型系统包括基本类型、数组等,而接口是定义对象结构的机制。接口描述对象外形,不涉及实现,可用于规定对象属性和方法。通过声明、实现接口,以及利用可选、只读属性,接口继承和合并,TypeScript增强了代码的健壮性和维护性。学习和掌握TypeScript的接口对于大型项目开发至关重要。
|
1天前
|
JavaScript 安全 前端开发
【亮剑】TypeScript 由于其强类型的特性,直接为对象动态添加属性可能会遇到一些问题
【4月更文挑战第30天】本文探讨了在 TypeScript 中安全地为对象动态添加属性的方法。基础方法是使用索引签名,允许接受任何属性名但牺牲了部分类型检查。进阶方法是接口扩展,通过声明合并动态添加属性,保持类型安全但可能导致代码重复。高级方法利用 OOP 模式的类继承,确保类型安全但增加代码复杂性。选择哪种方法取决于应用场景、代码复杂性和类型安全性需求。
|
1天前
|
JavaScript 前端开发
TypeScript基础类型
TypeScript基础类型
|
1天前
|
JavaScript 前端开发
typescript 混合类型
typescript 混合类型
|
1天前
|
JavaScript 前端开发 开发者
类型检查:结合TypeScript和Vue进行开发
【4月更文挑战第24天】TypeScript是JavaScript超集,提供类型注解等特性,提升代码质量和可维护性。Vue.js是一款高效前端框架,两者结合优化开发体验。本文指导如何配置和使用TypeScript与Vue:安装TypeScript和Vue CLI,创建Vue项目时选择TypeScript支持,配置`tsconfig.json`,编写`.tsx`组件,最后运行和构建项目。这种结合有助于错误检查和提升开发效率。
|
1天前
|
JavaScript 编译器 开发者
TypeScript中的类型推断机制:原理与实践
【4月更文挑战第23天】TypeScript的类型推断简化编码,提高代码可读性。编译器基于变量初始值或上下文推断类型,若新值不兼容则报错。文章深入探讨了类型推断原理和实践,包括基本类型、数组、函数参数与返回值、对象类型的推断,并提醒注意类型推断的限制,如非万能、类型兼容性和适度显式指定类型。了解这些能帮助更好地使用TypeScript。