当前位置: 首页 > article >正文

Typescript学习教程,从入门到精通,TypeScript 泛型与类型操作详解(二)(17)

TypeScript 泛型与类型操作详解(二)

本文将详细介绍 TypeScript 中的一些高级类型特性,包括条件类型、分布式条件类型、infer 关键字、内置工具类型、类型查询、类型断言、类型细化和类型守卫等。

1. 条件类型(Conditional Types)

1.1 定义

条件类型允许根据类型之间的关系在类型系统中进行条件判断。其语法类似于 JavaScript 中的三元运算符:

T extends U ? X : Y
  • 解释: 如果类型 T 可以赋值给类型 U,则结果类型为 X,否则为 Y

1.2 示例

type IsString<T> = T extends string ? true : false;type A = IsString<string>; // A 的类型为 true
type B = IsString<number>; // B 的类型为 false

2. 分布式条件类型(Distributive Conditional Types)

当条件类型应用于联合类型时,TypeScript 会将联合类型中的每个成员单独应用于条件类型,这种行为称为“分布式”。

2.1 示例

type ToArray<T> = T extends any ? T[] : never;type A = ToArray<string | number>; // A 的类型为 string[] | number[]

在这个例子中,ToArray 条件类型被应用于 string | number,结果为 string[] | number[]

3. infer 关键字

infer 关键字用于在条件类型中推断类型。它通常用于提取类型的一部分,例如函数的返回类型或参数类型。

3.1 示例:提取函数返回类型

type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;// 使用内置的 ReturnType
type Func = () => string;
type Result = ReturnType<Func>; // Result 的类型为 string

3.2 示例:提取数组元素类型

type ElementType<T> = T extends (infer E)[] ? E : T;type A = ElementType<string[]>; // A 的类型为 string
type B = ElementType<number>;   // B 的类型为 number

4. 内置工具类型(Utility Types)

TypeScript 提供了一些内置的工具类型,简化常见的类型操作。以下是一些常用的工具类型及其示例。

4.1 Partial<T>

将类型 T 的所有属性设为可选。

interface User {id: number;name: string;age?: number;
}type PartialUser = Partial<User>;
// PartialUser 等同于:
// {
//   id?: number;
//   name?: string;
//   age?: number;
// }

4.2 Required<T>

将类型 T 的所有属性设为必填。

type RequiredUser = Required<PartialUser>;
// RequiredUser 等同于:
// {
//   id: number;
//   name: string;
//   age: number;
// }

4.3 Readonly<T>

将类型 T 的所有属性设为只读。

type ReadonlyUser = Readonly<User>;
// ReadonlyUser 等同于:
// {
//   readonly id: number;
//   readonly name: string;
//   readonly age?: number;
// }

4.4 Record<K, T>

构造一个对象类型,其键为 K,值为 T

type StringNumberMap = Record<string, number>;
// StringNumberMap 等同于:
// {
//   [key: string]: number;
// }type UserRoles = Record<'admin' | 'user', boolean>;
// UserRoles 等同于:
// {
//   admin: boolean;
//   user: boolean;
// }

4.5 Pick<T, K>

从类型 T 中选取一组属性 K 构成新类型。

type PickUser = Pick<User, 'id' | 'name'>;
// PickUser 等同于:
// {
//   id: number;
//   name: string;
// }

4.6 Omit<T, K>

从类型 T 中排除一组属性 K 构成新类型。

type OmitUser = Omit<User, 'age'>;
// OmitUser 等同于:
// {
//   id: number;
//   name: string;
// }

4.7 Exclude<T, U>

从类型 T 中排除可赋值给 U 的部分。

type ExcludeString = Exclude<string | number | boolean, string | number>;
// ExcludeString 的类型为 boolean

4.8 Extract<T, U>

从类型 T 中提取可赋值给 U 的部分。

type ExtractString = Extract<string | number | boolean, string>;
// ExtractString 的类型为 string

4.9 NonNullable<T>

从类型 T 中排除 nullundefined

type NonNullableUser = NonNullable<User | null | undefined>;
// NonNullableUser 的类型为 User

4.10 Parameters<T>

提取函数类型 T 的参数类型组成的元组类型。

type Func = (a: string, b: number) => void;
type Params = Parameters<Func>;
// Params 的类型为 [string, number]

4.11 ConstructorParameters<T>

提取构造函数类型 T 的参数类型组成的元组类型。

type SomeClass = new (a: string, b: number) => void;
type ConstructorParams = ConstructorParameters<SomeClass>;
// ConstructorParams 的类型为 [string, number]

4.12 ReturnType<T>

提取函数类型 T 的返回类型。

type Func = () => string;
type Return = ReturnType<Func>;
// Return 的类型为 string

4.13 InstanceType<T>

提取构造函数类型 T 的实例类型。

type SomeClass = new () => { id: number };
type Instance = InstanceType<SomeClass>;
// Instance 的类型为 { id: number }

4.14 ThisParameterType<T>

提取函数类型 Tthis 参数类型。

type FuncWithThis = (this: Date, x: string) => void;
type ThisParam = ThisParameterType<FuncWithThis>;
// ThisParam 的类型为 Date

4.15 OmitThisParameter<T>

移除函数类型 Tthis 参数类型。

type FuncWithoutThis = OmitThisParameter<FuncWithThis>;
// FuncWithoutThis 的类型为 (x: string) => void

4.16 ThisType<T>

用于在对象字面量中指定 this 的上下文类型。

type ObjectWithThis = {id: number;getId(this: ObjectWithThis): number;
};const obj: ObjectWithThis = {id: 1,getId(this: ObjectWithThis) {return this.id;}
};

5. 类型查询(Type Queries)

类型查询使用 typeof 操作符来获取变量或属性的类型。

5.1 示例

let age = 25;
type AgeType = typeof age; // AgeType 的类型为 numberconst user = {id: 1,name: 'Alice'
};
type UserType = typeof user;
// UserType 的类型为 { id: number; name: string }

6. 类型断言(Type Assertions)

类型断言允许开发者手动指定一个值的类型,绕过 TypeScript 的类型检查。

6.1 <T>类型断言

let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;

6.2 as T 类型断言

let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;

6.3 类型断言的约束

类型断言不能违反类型层级。例如,不能将 number 断言为 string

6.4 const 类型断言

const 断言用于创建只读、字面量类型的值。

let x = "hello" as const;
// x 的类型为 "hello"let y = { id: 1, name: "Alice" } as const;
// y 的类型为 { readonly id: 1; readonly name: "Alice" }

6.5 ! 类型断言

! 用于断言某个值不是 nullundefined

function getLength(s?: string) {return s!.length;
}

7. 类型细化(Type Narrowing)

类型细化是通过代码逻辑来缩小变量的类型范围,常用的方法包括类型守卫、赋值语句分析、控制流分析等。

7.1 类型守卫(Type Guards)

7.1.1 typeof 类型守卫
function printId(id: string | number) {if (typeof id === "string") {console.log(id.toUpperCase());} else {console.log(id.toFixed(2));}
}
7.1.2 instanceof 类型守卫
function printDate(date: Date | string) {if (date instanceof Date) {console.log(date.toUTCString());} else {console.log(date.toUpperCase());}
}
7.1.3 自定义类型守卫
interface Cat {meow(): void;
}interface Dog {bark(): void;
}function isCat(animal: Cat | Dog): animal is Cat {return (animal as Cat).meow !== undefined;
}function speak(animal: Cat | Dog) {if (isCat(animal)) {animal.meow();} else {animal.bark();}
}

7.2 赋值语句分析

通过赋值语句,TypeScript 可以推断出变量的更具体类型。

let x: string | number;
x = "hello";
// x 的类型被细化为 stringx = 123;
// x 的类型被细化为 number

7.3 基于控制流的类型分析

TypeScript 会根据控制流(如 ifelsereturn 等)来推断变量的类型。

function example(x: string | number) {if (typeof x === "string") {// x 的类型为 stringconsole.log(x.toUpperCase());} else {// x 的类型为 numberconsole.log(x.toFixed(2));}
}

7.4 断言函数(Assertion Functions)

断言函数用于在运行时验证类型,并在验证失败时抛出错误。

function assertIsString(val: any): asserts val is string {if (typeof val !== "string") {throw new Error("Value is not a string");}
}function printString(s: string | number) {assertIsString(s);console.log(s.toUpperCase());
}

8. 案例代码

8.1 使用 PartialPick 创建部分属性对象

interface User {id: number;name: string;age: number;email: string;
}function updateUser(user: User, updates: Partial<Pick<User, 'name' | 'email'>>) {return { ...user, ...updates };
}const alice: User = { id: 1, name: "Alice", age: 30, email: "alice@example.com" };
const updatedAlice = updateUser(alice, { name: "Alicia", email: "alicia@example.com" });
// updatedAlice 的类型为 User

8.2 使用 ExcludeExtract 进行类型操作

type Mixed = string | number | boolean | string[];type NonString = Exclude<Mixed, string>; // NonString 的类型为 number | boolean | string[]
type OnlyString = Extract<Mixed, string>;  // OnlyString 的类型为 stringtype NonEmptyString = Exclude<OnlyString, ''>; // NonEmptyString 的类型为 string

8.3 使用 ReturnType 获取函数返回类型

type GreetFunc = (name: string) => string;type GreetReturn = ReturnType<GreetFunc>; // GreetReturn 的类型为 stringfunction greet(name: string): GreetReturn {return `Hello, ${name}!`;
}

8.4 使用 Parameters 获取函数参数类型

type SumFunc = (a: number, b: number) => number;type SumParams = Parameters<SumFunc>; // SumParams 的类型为 [number, number]function sum(a: number, b: number): number {return a + b;
}const params: SumParams = [1, 2];

8.5 使用 ThisParameterTypeOmitThisParameter 处理 this 参数

type FuncWithThis = (this: Date, x: string) => void;type ThisParam = ThisParameterType<FuncWithThis>; // ThisParam 的类型为 Datetype FuncWithoutThis = OmitThisParameter<FuncWithThis>; // FuncWithoutThis 的类型为 (x: string) => voidfunction example(this: ThisParam, x: string) {console.log(this.toUTCString(), x);
}const date = new Date();
example.call(date, "hello");

8.6 使用 ThisType 在对象字面量中指定 this 类型

type ObjectWithThis = {id: number;getId(this: ObjectWithThis): number;
};const obj: ObjectWithThis = {id: 1,getId(this: ObjectWithThis) {return this.id;}
};console.log(obj.getId());

8.7 使用 is 进行自定义类型守卫

interface Cat {meow(): void;
}interface Dog {bark(): void;
}function isCat(animal: Cat | Dog): animal is Cat {return (animal as Cat).meow !== undefined;
}function speak(animal: Cat | Dog) {if (isCat(animal)) {animal.meow();} else {animal.bark();}
}const cat: Cat = { meow: () => console.log("Meow!") };
const dog: Dog = { bark: () => console.log("Woof!") };speak(cat); // 输出: Meow!
speak(dog); // 输出: Woof!

8.8 使用 const 断言创建只读对象

const config = {apiUrl: "https://api.example.com",timeout: 3000
} as const;type ConfigType = typeof config;
// ConfigType 的类型为:
// {
//   readonly apiUrl: "https://api.example.com";
//   readonly timeout: 3000;
// }

8.9 使用 NonNullable 排除 nullundefined

type MaybeString = string | null | undefined;type DefiniteString = NonNullable<MaybeString>; // DefiniteString 的类型为 stringfunction getString(): MaybeString {return "Hello";
}const str: DefiniteString = getString()!;

8.10 使用 InstanceType 获取构造函数实例类型

class Person {constructor(public name: string) {}
}type PersonConstructor = typeof Person;type PersonInstance = InstanceType<PersonConstructor>; // PersonInstance 的类型为 Personconst person: PersonInstance = new Person("Alice");

总结

TypeScript 提供了丰富的类型操作工具,使得开发者能够在编译阶段进行更严格的类型检查和更灵活的类型操作。通过理解和应用这些高级类型特性,可以显著提升代码的可维护性和可靠性。

http://www.lryc.cn/news/2394334.html

相关文章:

  • 【iOS】源码阅读(五)——类类的结构分析
  • 基于CangjieMagic的RAG技术赋能智能问答系统
  • 算力租赁革命:弹性模式如何重构数字时代的创新门槛​
  • 图论回溯
  • 使用arthas热替换在线运行的java class文件
  • RFID测温芯片助力新能源产业安全与能效提升
  • S32K3 工具篇9:如何在无源码情况下灵活调试elf文件
  • Nacos 配置文件总结
  • ASP.NET Web Forms框架识别
  • LG P4119 [Ynoi2018] 未来日记 Solution
  • 流程引擎选型指南
  • 基于大模型预测带状疱疹(无并发症)诊疗方案的研究报告
  • 哈工大计统大作业-程序人生
  • 设计模式——装饰器设计模式(结构型)
  • 途景VR智拍APP:开启沉浸式VR拍摄体验
  • Linux环境搭建MCU开发环境
  • Android高级开发第一篇 - JNI(初级入门篇)
  • Kubernetes RBAC权限控制:从入门到实战
  • python实战项目71:基于Python的US News世界大学排名数据爬取
  • 【基础算法】高精度(加、减、乘、除)
  • 跨平台开发框架electron
  • Windows最快速打开各项系统设置大全
  • 嵌入式编译工具链熟悉与游戏移植
  • DeepSeek-R1-0528,官方的端午节特别献礼
  • LNMP环境中php7.2升级到php7.4
  • 001 flutter学习的注意事项及前期准备
  • FactoryBean 接口
  • CS144 - Lecture 1 记录
  • 【Redis】大key问题详解
  • 【数据结构】——二叉树--链式结构