首页 > 其他分享 >TypeScript一些特性让代码更优雅

TypeScript一些特性让代码更优雅

时间:2024-07-01 19:27:25浏览次数:3  
标签:TypeScript string name 代码 number 优雅 类型 属性

TypeScript不仅仅是JavaScript的类型超集,它还提供了一系列强大的高级特性,可以显著提高代码的质量和可维护性,掌握TypeScript的这些高级功能,不仅可以让你的代码更加健壮,还能大大提升你的开发效率。赶紧来看看吧!

一、深入理解 TypeScript 的高级类型推断

TypeScript 的类型推断系统非常强大,即使在复杂的情况下也能准确推断类型。这个特性减少了显式类型注解的需求,让你的代码更加简洁、易读。下面我们通过几个例子来了解 TypeScript 的高级类型推断是如何工作的。

 1. 常量断言(as const)

使用 as const 可以让 TypeScript 推断出更具体的类型。在下面的例子中,tuple 的类型被推断为 readonly [1, "two"],表示这个元组是只读的,并且元素类型和顺序固定。

let array = [1, "a"] as const; 
// TypeScript 推断 array 的类型为 readonly [1, "two"]

2. 自动推断数组类型

在下面的例子中,TypeScript 会自动推断 arr 的类型为 (number | string | boolean)[],因为数组中包含了数字、字符串和布尔值。

let arr = [1, 'a', true]; 
// TypeScript 推断 arr 的类型为 (number | string | boolean)[]

3. 泛型函数的类型推断

在泛型函数中,TypeScript 可以根据传入的参数自动推断出类型。以下是一个简单的泛型函数 identity,它接收一个参数并返回相同的值。TypeScript 会根据传入的对象自动推断 result 的类型为 { id: number; name: string; }。

function identity<T>(arg: T): T {
    return arg;
}

let result = identity({ userId: 1, name: "lvbin" });
// TypeScript 推断 result 的类型为 { id: number; name: string; }

二、灵活运用 TypeScript 条件类型

TypeScript 的条件类型让你可以根据条件创建类型,这对于定义依赖于其他类型的动态灵活类型非常有用。通过条件类型,你可以实现更多复杂的类型逻辑,增强代码的可扩展性和可维护性。下面我们通过一个例子来深入理解条件类型的应用。

1、条件类型的基本用法

条件类型的语法类似于三元运算符(condition ? trueType : falseType),根据条件表达式的结果选择类型。以下是一个简单的例子:

type codeType<T> = T extends "success" ? string : number;

在这个例子中,codeType根据 T 的值来确定其类型。如果 T 是 "success",则 codeType的类型为 string,否则为 number。

2、条件类型的应用

通过条件类型,我们可以更灵活地定义类型。以下示例展示了如何使用 codeType 类型:

let successMessage: codeType<"success"> = "Operation successful"; // 类型为 string
let errorMessage: codeType<"error"> = 404; // 类型为 number

通过这些例子,我们可以看到条件类型在定义复杂类型逻辑时的强大之处。它让我们可以根据不同的条件动态地生成类型,提高代码的灵活性和可维护性。

三、巧用 TypeScript 模板字面量类型

模板字面量类型(Template Literal Types)是 TypeScript 提供的一种强大工具,让你可以通过字符串字面量来创建更加表达性和易于管理的字符串类型。通过这种方式,你可以定义复杂的字符串组合类型,提升代码的可读性和可维护性。下面我们来看一个具体的例子。

1、模板字面量类型的基本用法

模板字面量类型允许你使用字符串字面量来创建新的类型。我们可以将多个字符串类型组合成一个新的字符串类型。例如:

type Color = "red" | "blue" | "orange";
type Size = "small"| "default" | "large";

type ColorSize = `${Color}-${Size}`;

在这个例子中,我们定义了两个基本类型 Color 和 Size,分别代表颜色和尺寸。然后,通过模板字面量类型 {Size},我们生成了一个新的类型 ColorSize,表示颜色和尺寸的组合。

2、 模板字面量类型的应用

使用模板字面量类型,我们可以轻松地创建复杂的字符串组合类型。以下是一个示例:

let item: ColorSize = "red-large"; // 合法
// let invalidItem: ColorSize = "green-small"; 
// 错误: 类型 '"green-small"' 不可分配给类型 'ColoredSize'。

在这个示例中,item 的类型是 ColoredSize,因此只能赋值为 "red-large", "red-default", "red-small" 或 "blue-large" ,"blue-default","blue-small"或”orange-large","orange-default","orange-small" 其中之一。如果尝试将 invalidItem 赋值为 "green-small",TypeScript 会报错,因为 "green-small" 不在 ColorSize 类型的定义范围内。

四、利用 TypeScript 类型谓词实现精准类型检查

TypeScript 的类型谓词(Type Predicates)提供了一种在条件块中缩小类型范围的方法,帮助你进行更准确的类型检查,从而减少类型断言的需求。通过类型谓词,你可以编写更健壮和易读的代码。下面通过一个例子来详细介绍类型谓词的使用。

1、类型谓词的基本用法

类型谓词的语法是 value is Type,用于函数的返回类型。当函数返回 true 时,TypeScript 会在其后的代码块中将变量的类型缩小到指定的类型。以下是一个示例:

function isString(value: unknown): value is string {
    return typeof value === "string";
}

在这个例子中,isString 函数检查传入的 value 是否为字符串。如果是,它返回 true,并告诉 TypeScript value 是 string 类型。

2、类型谓词的应用

类型谓词在处理联合类型时特别有用。下面是一个使用 isString 函数的示例,它可以区分传入的值是字符串还是数字:

function printValue(value: number | string) {
    if (isString(value)) {
        console.log(`String: ${value}`);
    } else {
        console.log(`Number: ${value}`);
    }
}

在这个 printValue 函数中,value 可以是 number 或 string。通过调用 isString(value),我们可以在 if 语句块中精确地将 value 的类型缩小为 string,在 else 语句块中则为 number。

类型谓词大大提高了代码的类型安全性和可读性,避免了不必要的类型断言。通过类型谓词,你可以在条件判断中精确地控制类型范围,使代码更加健壮。

五 、掌握 TypeScript 的索引访问类型

索引访问类型(Indexed Access Types)是 TypeScript 中一个强大的特性,它允许你从对象类型中获取属性类型,使你能够动态地访问属性的类型。通过这种方式,你可以更灵活地定义和使用类型。下面通过一个具体的例子来详细介绍索引访问类型的用法。

1、索引访问类型的基本用法

索引访问类型的语法类似于访问对象属性的语法。你可以使用 Type["property"] 的形式来获取对象类型的某个属性的类型。例如:

interface Person {
    name: string;
    age: number;
}

type NameType = Person["name"]; // string

在这个例子中,NameType 被定义为 Person 接口中 name 属性的类型,即 string。

2、索引访问类型的应用

通过索引访问类型,我们可以更简洁地获取并使用对象属性的类型。例如:

let personName: NameType = "king";

在这个示例中,personName 的类型被定义为 NameType,即 string。这种方式使得类型定义更加清晰和一致,避免了重复代码。

六、掌握 TypeScript 的 keyof 类型操作符

TypeScript 的 keyof 操作符用于创建一个对象类型的所有键的联合类型,这一特性能帮助你创建依赖于其他类型键的动态和灵活的类型定义。通过 keyof 操作符,你可以更加灵活地操作对象类型,提升代码的可维护性和可扩展性。下面我们通过一个具体的例子来详细介绍 keyof 操作符的用法。

1、keyof 操作符的基本用法

keyof 操作符会提取一个对象类型的所有键,并将这些键组成一个联合类型。以下是一个示例:

interface User {
    id: number;
    name: string;
    email: string;
}

type UserKeys = keyof User; // "id" | "name" | "email"

在这个例子中,UserKeys 被定义为 User 接口的所有键的联合类型,即 "id" | "name" | "email"。

2、keyof 操作符的应用

使用 keyof 操作符,我们可以创建更加灵活的类型定义。例如:

let key: UserKeys = "name";

在这个示例中,key 的类型是 UserKeys,所以它可以是 "id", "name" 或 "email" 之一。

3、动态对象属性

keyof 操作符在处理动态对象属性时特别有用。下面是一个示例,展示了如何使用 keyof 操作符和索引访问类型来创建灵活的类型:

function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
    return obj[key];
}

const user: User = { id: 1, name: "Alice", email: "[email protected]" };

let userName: string = getProperty(user, "name");
let userId: number = getProperty(user, "id");

在这个示例中,getProperty 函数使用了泛型和 keyof 操作符,使得我们可以安全地访问对象的属性,并且返回正确的类型。

keyof 操作符极大地增强了 TypeScript 类型系统的灵活性,使我们可以更动态地定义和操作类型。掌握这一特性,可以让你的代码更加健壮和易于维护。

七、 巧用 TypeScript 映射类型实现灵活类型转换

TypeScript 的映射类型(Mapped Types)可以将现有类型的属性转换为新类型。这一特性使得我们能够创建现有类型的变体,例如将所有属性设为可选或只读。通过映射类型,你可以更灵活地管理和操作类型,提高代码的可维护性。下面我们通过具体的例子来详细介绍映射类型的用法。

1、映射类型的基本用法

映射类型使用 keyof 操作符和索引签名来遍历和转换类型的所有属性。以下是一个示例,展示了如何将类型的所有属性设为只读:

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

在这个例子中,ReadOnly类型将类型 T 的所有属性设为只读。

2、映射类型的应用

我们可以使用 ReadOnly类型来创建一个只读的 User 类型实例:

interface User {
    id: number;
    name: string;
}

const readonlyUser: ReadOnly<User> = {
    id: 1,
    name: "John"
};

// readonlyUser.id = 2; 
// 错误: 无法给 'id' 赋值,因为它是只读属性。

在这个示例中,readonlyUser 是一个 ReadOnly类型的实例,所有属性都被设为只读,因此尝试修改属性值会导致编译错误。

映射类型提供了一种强大的方式来转换现有类型的属性,使你能够更灵活地定义类型。掌握这一特性,可以让你的代码更具弹性和可维护性。

八、掌握 TypeScript 的实用类型提升开发效率

TypeScript 提供了一些内置的实用类型(Utility Types),用于常见的类型转换操作,例如将所有属性设为可选(Partial)或只读(Readonly)。这些实用类型让我们可以更简洁地进行类型定义和转换,提高代码的可读性和可维护性。下面我们通过具体的例子来详细介绍这些实用类型的用法。

1、实用类型的基本用法

TypeScript 内置了多个实用类型,常用的包括 Partial和 Readonly。以下是它们的基本用法:

1.1、Partial:将类型 T 的所有属性设为可选。

interface User {
    id: number;
    name: string;
    email: string;
}

type PartialUser = Partial<User>; 
  // 所有属性都是可选的

在这个例子中,PartialUser 类型等价于:

interface PartialUser {
    id?: number;
    name?: string;
    email?: string;
}

1.2、Readonly:将类型 T 的所有属性设为只读。

type ReadonlyUser = Readonly<User>; 
  // 所有属性都是只读的

在这个例子中,ReadonlyUser 类型等价于:

interface ReadonlyUser {
    readonly id: number;
    readonly name: string;
    readonly email: string;
}

实用类型的应用

通过实用类型,我们可以轻松创建类型变体,提高开发效率。例如:

let user: PartialUser = { name: "John" };

let readonlyUser: ReadonlyUser = { 
    id: 1, 
    name: "web", 
    email: "[email protected]" 
};

// readonlyUser.id = 2; 
// 错误: 无法给 'id' 赋值,因为它是只读属性。

在这个示例中,user 是一个 PartialUser 类型的实例,其中所有属性都是可选的。readonlyUser 是一个 ReadonlyUser 类型的实例,其中所有属性都是只读的,因此尝试修改属性值会导致编译错误。

九、 巧用 TypeScript 的区分联合类型实现精确类型检查

TypeScript 的区分联合类型(Discriminated Unions)允许你通过共同的属性来区分多个相关类型。这一特性在处理具有相同属性但不同结构的类型集合时特别有用,使得类型检查更加简洁和准确。下面我们通过一个具体的例子来详细介绍区分联合类型的用法。

1、区分联合类型的基本用法

区分联合类型的关键在于为每个类型定义一个共同的属性,这个属性可以用来区分不同的类型。例如:

interface Square {
    kind: "square";
    size: number;
}

interface Rectangle {
    kind: "rectangle";
    width: number;
    height: number;
}

type Shape = Square | Rectangle;

在这个例子中,Square 和 Rectangle 这两个接口都有一个 kind 属性,用于区分是正方形还是矩形。Shape 类型是 Square 和 Rectangle 的联合类型。

2、区分联合类型的应用

通过区分联合类型,我们可以在处理联合类型时利用 kind 属性进行类型检查。例如,计算不同形状的面积:

function area(shape: Shape) {
    switch (shape.kind) {
        case "square":
            return shape.size ** 2;
        case "rectangle":
            return shape.width * shape.height;
    }
}

在这个 area 函数中,我们通过 switch 语句检查 shape.kind 的值,来确定当前形状的具体类型,并计算相应的面积。这种方式避免了类型断言,保证了类型检查的准确性。

3、区分联合类型的优势

使用区分联合类型有以下几个优势:

  • 类型安全:通过共同的区分属性,可以确保在处理不同类型时的类型安全性,避免类型错误。

  • 代码简洁:利用区分属性进行类型检查,使代码更加简洁和易读。

  • 扩展性强:可以轻松添加新的类型,并在现有代码基础上进行扩展。

区分联合类型是 TypeScript 提供的强大特性,可以帮助你在处理复杂类型集合时进行更精确的类型检查。掌握这一特性,可以让你的代码更加健壮和易于维护。

十、巧用 TypeScript 声明合并提升代码灵活性

TypeScript 的声明合并(Declaration Merging)允许你将多个声明合并为一个实体。这一特性非常适合增强现有类型,例如为已有接口添加新属性或合并同一模块的多个声明。通过声明合并,你可以更灵活地扩展和维护代码。下面我们通过具体的例子来详细介绍声明合并的用法。

1 、声明合并的基本用法

声明合并的核心是将多个同名的接口或模块声明合并为一个。在下面的示例中,我们定义了两次 User 接口:

interface User {
    id: number;
    name: string;
}

interface User {
    email: string;
}

TypeScript 会将这两个接口合并为一个,包含所有定义的属性:

const user: User = {
    id: 1,
    name: "web",
    email: "[email protected]"
};

在这个示例中,合并后的 User 接口包括 id、name 和 email 属性。

2、声明合并的优势

  • 增强灵活性:可以在不修改原始声明的情况下扩展类型,适应不同的开发需求。

  • 代码整洁:通过合并多个声明,避免了重复代码,使代码结构更清晰。

  • 提高可维护性:声明合并使得类型扩展更加方便,尤其是在使用第三方库时。

TypeScript 的声明合并是一个强大的特性,使你可以灵活地扩展和维护类型。通过声明合并,你可以在不修改原始声明的情况下,添加新属性或方法,提升代码的灵活性和可维护性。

结束

通过以上的介绍,我们可以看到 TypeScript 提供的这些高级特性,如类型推断、条件类型、模板字面量类型、类型谓词、索引访问类型、keyof 类型操作符、映射类型、实用类型、区分联合类型和声明合并等,如何帮助我们开发出更加健壮和可维护的应用。这些特性使 TypeScript 成为一个强大的工具,让你能够编写出更加简洁、高效的代码,从而使你的开发过程更加顺畅和愉快。

掌握这些 TypeScript 的高级特性,不仅可以提高你的编码效率,还能提升代码的质量和可维护性。在实际开发中,灵活运用这些特性,能够让你在面对复杂的需求时更加得心应手。

标签:TypeScript,string,name,代码,number,优雅,类型,属性
From: https://blog.csdn.net/lbking666666/article/details/140084218

相关文章

  • 前端页面防止它人代码调试
    今天分享一段JS 代码片段,是防止代码被调试或篡改的基础。老规矩,先阅读代码片段并思考,再看代码解析再思考,最后评论区留下你的见解!(()=>{function ban(){   setInterval(()=>{debugger;}, 50);   try {      ban();   } catch(err){}}ban();})(......
  • 用Python pynput库捕捉每一次组合键的优雅舞步
    哈喽,大家好,我是木头左!一、初识pynput:键盘与鼠标的监控利器当谈论计算机交互时,键盘和鼠标无疑是最常用的设备。无论是编写代码、浏览网页还是玩游戏,都依赖于这些输入设备与机器沟通。但在一些特殊的场景中,可能需要知道用户具体按下了哪些键,甚至是以何种顺序、何种速度进行操作......
  • Day61 代码随想录打卡|回溯算法篇---组合优化
    本篇是针对上一题的优化,因为在计算所有可能的组合结果时,不是每一条路径都是我们需要遍历的,如图,当n和k都为4的时候,其实最终的结果只有一个[1,2,3,4]是符合结果的。因此我们遍历的时候就不需要遍历每一条边,而是只需要沿着1,2,3,4的路径直接下来即可。那么我们怎么控制循环变量使得......
  • 给下拉框写cs代码
    protectedoverridevoidOnLoad(EventArgse){base.OnLoad(e);Control.Click+=Control_Click;container.DataChanged+=container_DataChanged;Control0.Click+=Control0_Click;stringsql1=@"selectmfgord......
  • [开源分享]好用的在线客服系统 PHP客服系统源码 聊天源码(开源代码+终身使用+安装教程
    源码介绍PHP在线客服系统源码采用全新UI,重新设计前端界面,后台采用php+mysql,免费开源源码。在线客服系统已成为企业与客户之间沟通的重要渠道。通过在线客服系统,企业可以方便地与客户进行实时沟通和解决问题,提升客户满意度。php客服系統源码主要功能要求:全新UI自动回复和机器......
  • 代码随想录算法训练营第四十三天 | 52.携带研究材料 518.零钱总和II 377.组合总和IV 7
    完全背包有N件物品和一个最多能被重量为W的背包,第i间物品的重量为weights[i],价值为value[i],每件物品都有无限个,求解将哪些物品装入背包里,物品价值总和最大遍历顺序:纯完全背包问题(即求装满背包后的最大价值)先遍历背包先遍历物品都是可以的和零一背包求解的最大不同就是遍历顺序......
  • sourcetree使用ssh拉取代码报错?看下是不是ssh客户端的问题以及相应的解决方案看这里~~
    相信很多软件开发的同学都很熟悉sourcetree,如果也有同学在使用过程中出现ssh拉取代码出现如下报错的问题这里比较头疼的是没法交互输入y确认缓存秘钥。Theserver'shostkeyisnotcachedintheregistry.Youhavenoguaranteethattheserveristhecomputeryouthi......
  • 代码随想录算法训练营第四十二天 | 1049最后一块石头的重量II 494.目标和 474.一和零
    1049.最后一块石头的重量题目链接文章讲解视频讲解解题思路:  将石头尽量分为相等的两堆,两堆最差即为所求结果  石头的重量就是石头的价值动规五部曲:dp[j]:表示背包容量为j时可以装的石头的总价值递推公式:dp[j]=max(dp[j],dp[j-stones[i]]+stones[i]初始化:均......
  • BEV感知算法:LSS论文与代码详解
    BEV感知算法:LSS论文与代码详解0. 前言最近几年,BEV感知是自动驾驶领域中一个非常热门研究方向,其核心思想是把多路传感器的数据转换到统一的BEV空间中去提取特征,实现目标检测、地图构建等任务。如何把多路相机的数据从二维的图像视角转换到三维的BEV视角?LSS提出一种显示估......
  • DWA(Dynamic Window Approach)局部路径规划算法详解及代码实现
    DWA(Dynamic Window Approach)局部路径规划算法详解及代码实现二、算法原理一句话概况,就是假定机器人当前以若干组容许范围内的速度(差速轮为例:线速度V,角速度W)进行移动,并对这若干组速度进行轨迹计算,得到若干组轨迹,再根据若干条评分机制选择最好的轨迹所对应的速度作为dwa输......