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 类型演算,并在实际开发中得到应用。

目录
相关文章
|
3月前
|
JavaScript
typeScript进阶(9)_type类型别名
本文介绍了TypeScript中类型别名的概念和用法。类型别名使用`type`关键字定义,可以为现有类型起一个新的名字,使代码更加清晰易懂。文章通过具体示例展示了如何定义类型别名以及如何在函数中使用类型别名。
45 1
typeScript进阶(9)_type类型别名
|
3月前
|
JavaScript
typeScript基础(2)_any任意值类型和类型推论
本文介绍了TypeScript中的`any`任意值类型,它可以赋值为其他任何类型。同时,文章还解释了TypeScript中的类型推论机制,即在没有明确指定类型时,TypeScript如何根据变量的初始赋值来推断其类型。如果变量初始化时未指定类型,将被推断为`any`类型,从而允许赋予任何类型的值。
59 4
|
3月前
|
JavaScript
typeScript基础(5)_对象的类型-interfaces接口
本文介绍了TypeScript中接口(interfaces)的基本概念和用法,包括如何定义接口、接口的简单使用、自定义属性、以及如何使用`readonly`关键字定义只读属性。接口在TypeScript中是定义对象形状的重要方式,可以规定对象的必有属性、可选属性、自定义属性和只读属性。
43 1
|
2月前
|
JavaScript 前端开发 安全
深入理解TypeScript:增强JavaScript的类型安全性
【10月更文挑战第8天】深入理解TypeScript:增强JavaScript的类型安全性
52 0
|
2月前
|
JavaScript 前端开发 开发者
深入理解TypeScript:类型系统与实用技巧
【10月更文挑战第8天】深入理解TypeScript:类型系统与实用技巧
|
3月前
|
存储 JavaScript
typeScript进阶(11)_元组类型
本文介绍了TypeScript中的元组(Tuple)类型,它是一种特殊的数组类型,可以存储不同类型的元素。文章通过示例展示了如何声明元组类型以及如何给元组赋值。元组类型在定义时需要指定数组中每一项的类型,且在赋值时必须满足这些类型约束。此外,还探讨了如何给元组类型添加额外的元素,这些元素必须符合元组类型中定义的类型联合。
48 0
|
3月前
|
JavaScript
typeScript进阶(10)_字符串字面量类型
本文介绍了TypeScript中的字符串字面量类型,这种类型用来限制变量只能是某些特定的字符串字面量。通过使用`type`关键字声明,可以确保变量的值限定在预定义的字符串字面量集合中。文章通过示例代码展示了如何声明和使用字符串字面量类型,并说明了它在函数默认参数中的应用。
38 0
|
19天前
|
JavaScript 安全 前端开发
TypeScript类型声明:基础与进阶
通过本文的介绍,我们详细探讨了TypeScript的基础与进阶类型声明。从基本数据类型到复杂的泛型和高级类型,TypeScript提供了丰富的工具来确保代码的类型安全和可维护性。掌握这些类型声明能够帮助开发者编写更加健壮和高效的代码,提高开发效率和代码质量。希望本文能为您在使用TypeScript时提供实用的参考和指导。
30 2
|
1月前
|
JavaScript 开发者
在 Babel 插件中使用 TypeScript 类型
【10月更文挑战第23天】可以在 Babel 插件中更有效地使用 TypeScript 类型,提高插件的开发效率和质量,减少潜在的类型错误。同时,也有助于提升代码的可理解性和可维护性,使插件的功能更易于扩展和升级。
|
2月前
|
JavaScript 前端开发
TypeScript【类型别名、泛型】超简洁教程!再也不用看臭又长的TypeScript文档了!
【10月更文挑战第11天】TypeScript【类型别名、泛型】超简洁教程!再也不用看臭又长的TypeScript文档了!