TypeScript 中的 `extends` 条件类型:定义与应用

🤍 前端开发工程师、技术日更博主、已过CET6

🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1

🕠 牛客 高级专题作者、打造专栏《前端面试必备》《2024面试高频手撕题》《前端求职突破计划》

🍚 蓝桥云课 签约作者、上架课程《Vue.js 和 Egg.js 开发企业级健康管理项目》《带你从入门到实战全面掌握 uni-app》

文章目录

TypeScript 的条件类型是高级类型系统中的一个重要特性,它允许根据条件动态地选择类型。extends 关键字在条件类型中用于定义类型之间的关系,从而实现类型选择和类型推导。本文将详细介绍如何定义和使用 extends 条件类型,并通过实际案例展示其强大的功能。

一、条件类型的定义

(一)基本语法

条件类型的基本语法如下:

typescript 复制代码
T extends U ? X : Y
  • T 是需要检查的类型。
  • U 是参考类型。
  • X 是当 TU 的子类型时选择的类型。
  • Y 是当 T 不是 U 的子类型时选择的类型。

(二)示例

以下是一个简单的条件类型示例:

typescript 复制代码
type IsNumber<T> = T extends number ? true : false;

type IsNumberResult1 = IsNumber<42>; // true
type IsNumberResult2 = IsNumber<string>; // false

在这个例子中,IsNumber 是一个条件类型,它检查传入的类型 T 是否是 number 的子类型。如果是,则结果为 true;否则,结果为 false

二、extends 条件类型的高级用法

(一)联合类型与条件类型

条件类型可以与联合类型结合使用,实现更复杂的类型选择逻辑。

示例:根据联合类型选择结果
typescript 复制代码
type IsStringOrNumber<T> = T extends string | number ? true : false;

type IsStringOrNumberResult1 = IsStringOrNumber<42>; // true
type IsStringOrNumberResult2 = IsStringOrNumber<string>; // true
type IsStringOrNumberResult3 = IsStringOrNumber<boolean>; // false

在这个例子中,IsStringOrNumber 检查传入的类型 T 是否是 stringnumber 的联合类型。如果是,则结果为 true;否则,结果为 false

(二)递归条件类型

条件类型可以递归地定义,实现更复杂的类型逻辑。

示例:深度只读类型
typescript 复制代码
type DeepReadonly<T> = T extends object
  ? { readonly [P in keyof T]: DeepReadonly<T[P]> }
  : T;

type MyObject = {
  a: number;
  b: {
    c: string;
    d: boolean;
  };
};

type DeepReadonlyMyObject = DeepReadonly<MyObject>;
// 等价于:
// type DeepReadonlyMyObject = {
//   readonly a: number;
//   readonly b: {
//     readonly c: string;
//     readonly d: boolean;
//   };
// }

在这个例子中,DeepReadonly 是一个递归条件类型,它将对象的每个属性递归地转换为只读类型。

(三)分配条件类型

当条件类型与联合类型结合时,TypeScript 会自动将联合类型分配到条件类型中,实现类型分配。

示例:分配条件类型
typescript 复制代码
type Flatten<T> = T extends any[] ? T[number] : T;

type FlattenResult1 = Flatten<[1, 2, 3]>; // 1 | 2 | 3
type FlattenResult2 = Flatten<string>; // string

在这个例子中,Flatten 是一个条件类型,它检查传入的类型 T 是否是数组类型。如果是,则提取数组的元素类型;否则,直接返回 T

(四)使用 infer 关键字

infer 关键字用于在条件类型中推导类型,通常用于提取类型的一部分。

示例:提取函数返回值类型
typescript 复制代码
type GetReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

type GetReturnTypeResult1 = GetReturnType<() => string>; // string
type GetReturnTypeResult2 = GetReturnType<(a: number, b: string) => boolean>; // boolean

在这个例子中,GetReturnType 是一个条件类型,它使用 infer 关键字推导函数的返回值类型。

三、实际应用案例

(一)实现一个类型安全的 omit 函数

omit 函数用于从对象中移除某些属性。通过条件类型,可以实现一个类型安全的 omit 函数。

typescript 复制代码
type Omit<T, K extends keyof T> = {
  [P in keyof T as P extends K ? never : P]: T[P];
};

function omit<T, K extends keyof T>(obj: T, keys: K[]): Omit<T, K> {
  const result = {} as Omit<T, K>;
  for (const key in obj) {
    if (!keys.includes(key as K)) {
      result[key as keyof Omit<T, K>] = obj[key];
    }
  }
  return result;
}

const obj = { a: 1, b: 2, c: 3 };
const result = omit(obj, ['b', 'c']); // { a: 1 }

在这个例子中,Omit 是一个条件类型,它通过类型映射和 infer 关键字实现类型安全的属性移除。

(二)实现一个类型安全的 pick 函数

pick 函数用于从对象中提取某些属性。通过条件类型,可以实现一个类型安全的 pick 函数。

typescript 复制代码
type Pick<T, K extends keyof T> = {
  [P in K]: T[P];
};

function pick<T, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> {
  const result = {} as Pick<T, K>;
  for (const key of keys) {
    result[key] = obj[key];
  }
  return result;
}

const obj = { a: 1, b: 2, c: 3 };
const result = pick(obj, ['a', 'c']); // { a: 1, c: 3 }

在这个例子中,Pick 是一个条件类型,它通过类型映射实现类型安全的属性提取。

四、最佳实践

(一)保持类型逻辑清晰

条件类型可以实现复杂的类型逻辑,但过度使用可能会导致代码难以理解和维护。尽量保持类型逻辑清晰和简洁。

(二)合理使用 infer 关键字

infer 关键字是条件类型中的强大工具,但需要谨慎使用。确保推导的类型逻辑符合预期。

(三)结合工具类型

TypeScript 提供了许多内置的工具类型(如 PartialReadonlyOmit 等),可以结合这些工具类型实现更强大的类型功能。

五、总结

extends 条件类型是 TypeScript 中一个强大且灵活的特性,允许根据条件动态地选择类型。通过条件类型,可以实现复杂的类型逻辑,如联合类型的选择、递归类型定义、分配条件类型和类型推导。合理使用条件类型可以显著提升代码的类型安全性和可维护性。希望本文能够帮助你更好地理解和使用 extends 条件类型。

相关推荐
众创岛2 小时前
iframe的属性获取
开发语言·javascript·ecmascript
echome8883 小时前
JavaScript Promise 与 async/await 实战:5 个高频异步编程场景的优雅解决方案
开发语言·javascript·ecmascript
摸鱼仙人~4 小时前
Math.js 使用教程
开发语言·javascript·ecmascript
wuhen_n5 小时前
LangChain Agents 实战:构建智能文件管理助手
前端·javascript·人工智能·langchain·ai编程
. . . . .5 小时前
抽象语法树 AST
javascript
zero15976 小时前
TypeScript 快速实战系列:基础入门|TypeScript 核心语法 1 小时吃透(必备基础)
javascript·typescript·大模型编程语言
zzginfo7 小时前
JavaScript 解构赋值
开发语言·javascript·ecmascript
邂逅星河浪漫8 小时前
【JavaScript】==和===区别详解
java·javascript·==·===
Dxy12393102168 小时前
JavaScript 如何捕获异常:从基础到进阶的完整指南
开发语言·javascript·udp