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

发布时间:2024年01月11日

? 专栏介绍

TypeScript是一种由微软开发的开源编程语言,它是JavaScript的超集,意味着任何有效的JavaScript代码都是有效的TypeScript代码。TypeScript通过添加静态类型和其他特性来增强JavaScript,使其更适合大型项目和团队开发。

在TypeScript专栏中,我们将深入探讨TypeScript的各个方面,包括语法、类型系统、模块化、面向对象编程等。我们将介绍如何使用TypeScript来构建可维护、可扩展和高效的应用程序。

TypeScript是一种开源的编程语言,它是JavaScript的超集,意味着所有的JavaScript代码都可以在TypeScript中运行。TypeScript添加了静态类型检查和其他一些新特性,以提高代码的可读性、可维护性和可扩展性。
在这里插入图片描述


引言

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

基本概念

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

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

类型推断与上下文

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

例如,在以下代码中:

let x = 10;

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

类型操作符

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

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

let x: number | string;

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

条件类型

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

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

type Result<T> = T extends number ? string : boolean;

function getResult<T>(input: T): Result<T> {
  if (typeof input === "number") {
    return "number";
  } else {
    return true;
  }
}

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

映射类型

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

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

type ReadonlyObject<T> = {
  readonly [P in keyof T]: T[P];
};

const obj: 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 操作符来判断一个值的类型,并在代码块中使用该类型:

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

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

类型演算的应用

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

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

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

操作符

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

typeof 操作符

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

let x = 10;
let y: typeof x; // y 的类型为 number

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

keyof 关键字

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

type Person = {
 name: string;
 age: number;
};

type PersonKeys = keyof Person; // PersonKeys 的类型为 "name" | "age"

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

in 关键字

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

type Fruit = "apple" | "banana" | "orange";

type FruitInfo = {
 [P in Fruit]: number;
};

const fruitCount: 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> 用于从类型 T 中排除指定属性 K。它会创建一个新的类型,其中排除了属性 K。

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

在上述代码中,Omit<Person, ‘address’> 从 Person 类型中排除了属性 ‘address’。

Pick<T, K>

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

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

在上述代码中,Pick<Person, ‘name’ | ‘age’> 从 Person 类型中选择了属性 ‘name’ 和 ‘age’。

Record<K, T>

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

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

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

Partial<T>

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

type Person = {
  name: string;
  age: number;
};

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

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

Required<T>

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

type PartialPerson = {
  name?: string;
  age?: number;
};

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

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

Readonly<T>

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

type Person = {
  name: string;
  age: number;
};

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

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

Exclude<T, U>

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

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

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

Extract<T, U>

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

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

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

NonNullable<T>

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

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

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

ReturnType<T>

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

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

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

InstanceType<T>

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

class Person {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
}

type PersonInstance = InstanceType<typeof Person>;
// PersonInstance 的类型为 Person

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

Awaited<T>

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

async function fetchData(): Promise<string> {
  return "Data";
}

type AwaitedData = Awaited<ReturnType<typeof fetchData>>;
// AwaitedData 的类型为 string

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

Parameters<T>

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

function greet(name: string, age: number): void {
  console.log(`Hello, ${name}! You are ${age} years old.`);
}

type GreetParams = Parameters<typeof greet>;
// GreetParams 的类型为 [string, number]

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

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

总结

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


😶 写在结尾

前端设计模式专栏
在这里插入图片描述
设计模式是软件开发中不可或缺的一部分,它们帮助我们解决了许多常见问题,并提供了一种优雅而可靠的方式来构建应用程序。在本专栏中,我们介绍了所有的前端设计模式,包括观察者模式、单例模式、策略模式等等。通过学习这些设计模式,并将其应用于实际项目中,我们可以提高代码的可维护性、可扩展性和可重用性。希望这个专栏能够帮助你在前端开发中更好地应用设计模式,写出高质量的代码。点击订阅前端设计模式专栏

Vue专栏
在这里插入图片描述
Vue.js是一款流行的JavaScript框架,用于构建用户界面。它采用了MVVM(Model-View-ViewModel)的架构模式,通过数据驱动和组件化的方式,使开发者能够更轻松地构建交互性强、可复用的Web应用程序。在这个专栏中,我们将深入探讨Vue.js的核心概念、组件开发、状态管理、路由和性能优化等方面的知识。我们将学习如何使用Vue.js构建响应式的用户界面,并探索其强大的生态系统,如Vue Router和Vuex、Pinia。通过学习这些内容,你将能够成为一名熟练的Vue.js开发者,并能够应用这些知识来构建复杂而高效的Web应用程序。点击订阅Vue专栏

JavaScript(ES6)专栏在这里插入图片描述
JavaScript是一种广泛应用于网页开发和后端开发的脚本语言。它具有动态性、灵活性和易学性的特点,是构建现代Web应用程序的重要工具之一。在这个专栏中,我们将深入探讨JavaScript语言的基本语法、DOM操作、事件处理、异步编程以及常见算法和数据结构等内容。此外,我们还将介绍ES6(ECMAScript 2015)及其后续版本中引入的新特性,如箭头函数、模块化、解构赋值等。通过学习这些内容,你将能够成为一名熟练的JavaScript开发者,并能够应用这些知识来构建出高质量和可维护的Web应用程序。点击订阅JavaScript(ES6)专栏

文章来源:https://blog.csdn.net/csdn9_14/article/details/135514222
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。