LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

12个编写整洁TypeScript代码的技巧

admin
2024年11月18日 23:9 本文热度 315

本文将探讨十二个用于编写整洁 TypeScript 代码的技巧,并通过示例展示它们的工作原理以及为何有用。在你自己的 TypeScript 代码中使用这些技巧,可以创建更健壮、更易于维护的应用程序,使其更易于理解和调试。

1. 使用类型注解

TypeScript 是一种静态类型语言,这意味着你可以为变量和函数定义类型。使用类型注解有助于在开发过程早期捕获错误,并提高代码的可读性。

以下是 TypeScript 中类型注解的一些示例:

// 显式指定变量的数据类型
let count: number = 0;

// 显式指定函数参数和返回值的数据类型
function addNumbers(a: number, b: number): number {
    return a + b;
}

// 显式指定类属性的数据类型
class Person {
    name: string;
    age: number;
    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }
    getDetails(): string {
        return `${this.name} is ${this.age} years old.`;
    }
}

在这些示例中,我们使用类型注解来指定变量、函数参数、函数返回值和类属性的数据类型。类型注解写在变量、参数或属性名之后,用冒号(:)分隔,后面跟着所需的数据类型。

2. 使用枚举

枚举是 TypeScript 的一个强大功能,允许你定义一组命名常量。它们可以使你的代码更具可读性和可维护性,并减少因魔术数字(magic numbers)导致错误的可能性。

以下是在 TypeScript 中如何使用枚举的示例:

enum Color {
    Red = "RED",
    Green = "GREEN",
    Blue = "BLUE"
}

function printColor(color: Color): void {
    console.log(`The color is ${color}`);
}

printColor(Color.Red); // 输出:The color is RED

在这个示例中,我们定义了一个名为Color的枚举,它包含三个命名常量:RedGreenBlue。每个常量都有一个关联的值,可以是字符串或数字。然后我们定义了一个名为printColor的函数,它接受一个Color参数,并使用该参数值在控制台中记录一条消息。

当我们使用Color.Red常量作为参数调用printColor函数时,它会在控制台中记录消息 "The color is RED"。

3. 使用可选链

可选链是 TypeScript 的一个特性,允许你安全地访问嵌套属性和方法,而无需担心中间值是否为nullundefined。这有助于减少运行时错误的可能性,并使你的代码更健壮。

以下是在 TypeScript 中如何使用可选链的示例:

interface Person {
    name: string;
    address?: {
        street: string;
        city: string;
        state: string;
    };
}

const person1: Person = {
    name: "John",
    address: {
        street: "123 Main St",
        city: "Anytown",
        state: "CA",
    },
};

const person2: Person = {
    name: "Jane",
};

console.log(person1?.address?.city); // 输出:Anytown
console.log(person2?.address?.city); // 输出:undefined

在这个示例中,我们有一个名为Person的接口,它定义了一个可选的address属性,该属性是一个具有streetcitystate属性的对象。然后我们创建了两个Person类型的对象,一个带有address属性,一个没有。

我们使用可选链安全地访问address对象的city属性,即使address属性或其任何子属性为undefinednull。如果链中的任何属性为undefinednull,表达式将返回undefined而不是抛出TypeError

4. 使用空值合并运算符

空值合并运算符是 TypeScript 的另一个特性,可以使你的代码更健壮。它允许你在变量或表达式为nullundefined时提供默认值,而不依赖于假值(falsy values)。

以下是在 TypeScript 中如何使用空值合并运算符的示例:

let value1: string | null = null;
let value2: string | undefined = undefined;
let value3: string | null | undefined = "hello";

console.log(value1?? "default value"); // 输出:"default value"
console.log(value2?? "default value"); // 输出:"default value"
console.log(value3?? "default value"); // 输出:"hello"

在这个示例中,我们有三个可能包含nullundefined值的变量。我们使用空值合并运算符(??)来检查值是否为nullundefined,并在这种情况下提供默认值。

在前两种情况下,变量value1value2分别为nullundefined,因此返回默认值。在第三种情况下,变量value3包含一个非null/非undefined值,因此返回该值而不是默认值。

5. 使用泛型

泛型是 TypeScript 的一个强大功能,允许你编写可重用的代码,该代码可以与不同类型一起工作。它们可以帮助减少代码重复并提高代码的可维护性。

以下是在 TypeScript 中如何使用泛型的示例:

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

let output1 = identity<string>("hello"); // 输出:"hello"
let output2 = identity<number>(42); // 输出:42

在这个示例中,我们定义了一个名为identity的函数,它接受一个类型参数T并返回与传入值相同类型的值。该函数可以处理任何类型的数据,实际的数据类型在函数调用时指定。

然后我们用两种不同的数据类型调用identity函数:一个字符串和一个数字。函数返回与传入值相同类型的值,因此output1是字符串类型,output2是数字类型。

6. 使用接口

接口是 TypeScript 的另一个强大功能,可以帮助你编写整洁且可读的代码。它们允许你为类、对象或函数定义契约,这可以帮助你避免常见错误并使你的代码更具自文档性。

以下是在 TypeScript 中如何使用接口的示例:

interface Person {
    firstName: string;
    lastName: string;
    age?: number;
}

function sayHello(person: Person): void {
    console.log(`Hello, ${person.firstName} ${person.lastName}!`);
    if (person.age) {
        console.log(`You are ${person.age} years old.`);
    }
}

let person1 = { firstName: "John", lastName: "Doe", age: 30 };
let person2 = { firstName: "Jane", lastName: "Doe" };

sayHello(person1); // 输出:"Hello, John Doe! You are 30 years old."
sayHello(person2); // 输出:"Hello, Jane Doe!"

在这个示例中,我们定义了一个名为Person的接口,它指定了person对象的形状,包括firstNamelastName属性以及一个可选的age属性。然后我们定义了一个名为sayHello的函数,它接受一个Person对象作为参数,并在控制台中打印问候语。

我们创建了两个与Person接口形状匹配的对象,并将它们传递给sayHello函数。该函数能够访问每个对象的firstNamelastName属性,并在将age属性打印到控制台之前检查它是否存在。

7. 使用解构

解构是一种简写语法,允许你从数组和对象中提取值。它可以使你的代码更具可读性和简洁性,并减少因变量名不匹配导致错误的可能性。

以下是在 TypeScript 中如何使用解构的一些示例:

对象解构

let person = { firstName: "John", lastName: "Doe", age: 30 };
let { firstName, lastName } = person;

console.log(firstName); // 输出:"John"
console.log(lastName); // 输出:"Doe"

在这个示例中,我们创建了一个名为person的对象,具有三个属性。然后我们使用对象解构来提取firstNamelastName属性,并将它们分配给同名变量。这使我们能够更轻松地访问这些属性,并且使用更少的代码。

数组解构

let numbers = [12345];
let [first, second,, fourth] = numbers;

console.log(first); // 输出:1
console.log(second); // 输出:2
console.log(fourth); // 输出:4

在这个示例中,我们创建了一个数字数组,并使用数组解构来提取第一、第二和第四个元素,并将它们分配给变量。我们使用解构模式中的空槽跳过第三个元素。这使我们能够更轻松地访问数组中的特定元素,并且使用更少的代码。

解构也可以与函数参数一起使用,允许你从作为参数传递的对象中提取特定值:

function greet({ firstName, lastName }: { firstName: string, lastName: string }): void {
    console.log(`Hello, ${firstName} ${lastName}!`);
}

let person = { firstName: "John", lastName: "Doe", age: 30 };
greet(person); // 输出:"Hello, John Doe!"

在这个示例中,我们定义了一个名为greet的函数,它使用解构语法在函数参数中接受一个具有firstNamelastName属性的对象。然后我们传入一个person对象,greet函数能够提取firstNamelastName属性并在控制台日志语句中使用它们。

8. 使用异步/等待

异步/等待是 TypeScript 的一个强大功能,允许你编写看起来和行为类似于同步代码的异步代码。它可以提高代码的可读性并减少因回调地狱(callback hell)导致错误的可能性。

以下是在 TypeScript 中如何使用异步/等待的示例:

async function getData({
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();
    return data;
}

getData().then((data) => {
    console.log(data);
}).catch((error) => {
    console.error(error);
});

在这个示例中,我们定义了一个名为getData的异步函数,它向一个 API 发出fetch请求,并使用await关键字等待响应。然后我们使用json()方法解析响应,并再次使用await等待结果。最后,我们返回数据对象。

然后我们调用getData()函数,并使用then()方法处理返回的数据,或者使用catch()方法处理可能发生的任何错误。

9. 使用函数式编程技术

函数式编程技术,如不可变性、纯函数和高阶函数,可以帮助你编写整洁且可维护的代码。它们可以帮助减少副作用并使你的代码更具可预测性和可测试性。

纯函数:纯函数是没有副作用且对于相同输入始终返回相同输出的函数。纯函数使代码更易于理解,并有助于防止错误。以下是一个纯函数的示例:

function add(a: number, b: number): number {
    return a + b;
}

高阶函数:高阶函数是接受一个或多个函数作为参数或返回一个函数作为结果的函数。高阶函数可用于创建可重用代码并简化复杂逻辑。以下是一个高阶函数的示例:

function map<TU>(arr: T[], fn: (arg: T) => U): U[] {
    const result = [];
    for (const item of arr) {
        result.push(fn(item));
    }
    return result;
}

const numbers = [12345];
const doubledNumbers = map(numbers, (n) => n * 2);
console.log(doubledNumbers); // 输出:[2, 4, 6, 8, 10]

在这个示例中,map函数接受一个数组和一个函数作为参数,并将该函数应用于数组中的每个元素,返回一个包含结果的新数组。

不可变数据:不可变数据是创建后不能更改的数据。在函数式编程中,强调不可变性以防止副作用并使代码更易于理解。以下是使用不可变数据的示例:

const numbers = [12345];
const newNumbers = [...numbers, 6];

console.log(numbers); // 输出:[1, 2, 3, 4, 5]
console.log(newNumbers); // 输出:[1, 2, 3, 4, 5, 6]

在这个示例中,我们使用展开运算符创建一个新数组,在末尾添加一个新元素,而不修改原始数组。

10. 使用 Pick

Pick是 TypeScript 的一个实用类型,允许我们从现有类型创建新类型,使代码更易于重用和维护。它还通过确保新类型仅包含我们打算使用的属性来帮助防止错误。

以下是一个示例:

interface User {
    name: string;
    email: string;
    age: number;
    isAdmin: boolean;
}

type UserSummary = Pick<User, 'name' | 'email'>;

const user: User = {
    name: 'John Doe',
    email: 'johndoe@example.com',
    age: 30,
    isAdmin: false,
};

const summary: UserSummary = {
    name: user.name,
    email: user.email,
};

console.log(summary); // 输出:{ name: 'John Doe', email: 'johndoe@example.com' }

在这个示例中,我们定义了一个名为User的接口,具有几个属性。然后我们使用Pick实用类型定义一个新类型UserSummary,它从User接口中仅选择nameemail属性。

然后我们创建一个具有User接口所有属性的对象user,并使用nameemail属性创建一个新的UserSummary类型的对象summary

11. 使用 Omit

Omit是 TypeScript 的一个实用类型,允许我们从现有类型创建新类型,同时确保排除某些属性。当处理复杂接口时,在某些情况下某些属性可能不需要,这会很有帮助。它还可以通过确保某些属性不会意外包含来帮助防止错误。

以下是一个示例:

interface User {
    name: string;
    email: string;
    age: number;
    isAdmin: boolean;
}

type UserWithoutEmail = Omit<User, 'email'>;

const user: User = {
    name: 'John Doe',
    email: 'johndoe@example.com',
    age: 30,
    isAdmin: false,
};

const userWithoutEmail: UserWithoutEmail = {
    name: user.name,
    age: user.age,
    isAdmin: user.isAdmin,
};

console.log(userWithoutEmail); // 输出:{ name: 'John Doe', age: 30, isAdmin: false }

在这个示例中,我们定义了一个名为User的接口,具有几个属性。然后我们使用Omit实用类型定义一个新类型UserWithoutEmail,它从User接口中省略email属性。然后我们创建一个具有User接口所有属性的对象user,并使用nameageisAdmin属性创建一个新的UserWithoutEmail类型的对象userWithoutEmail

12. 使用可辨识联合

可辨识联合是 TypeScript 的一个特性,允许我们根据特定属性或属性组合对可以具有不同形状的类型进行建模,并使用switch语句以类型安全的方式处理它们。它是 TypeScript 的一个强大功能,可以使你的代码更具表现力和可维护性。

以下是一个示例:

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

interface Circle {
    kind: 'circle';
    radius: number;
}

interface Triangle {
    kind: 'triangle';
    base: number;
    height: number;
}

type Shape = Square | Circle | Triangle;

function area(shape: Shape{
    switch (shape.kind) {
        case 'square':
            return shape.size * shape.size;
        case 'circle':
            return Math.PI * shape.radius * shape.radius;
        case 'triangle':
            return 0.5 * shape.base * shape.height;
    }
}

const square: Square = { kind: 'square', size: 10 };
const circle: Circle = { kind: 'circle', radius: 5 };
const triangle: Triangle = { kind: 'triangle', base: 10, height: 8 };

console.log(area(square)); // 输出:100
console.log(area(circle)); // 输出:78.53981633974483
console.log(area(triangle)); // 输出:40

在这个示例中,我们定义了三个接口SquareCircleTriangle,每个接口代表一种不同的形状。然后我们定义了一个联合类型Shape,它可以是SquareCircleTriangle中的任意一种。

我们定义了一个函数area,它接受一个Shape类型的参数,并使用switch语句根据形状的kind属性计算其面积。kind属性被用作可辨识属性,因为它唯一地标识了每种形状类型。

然后我们创建了三个对象,每种形状一个,并使用每个对象作为参数调用area函数来计算面积。

总结

这些用于编写整洁 TypeScript 代码的技巧可以帮助你编写更具表现力、可维护且无错误的代码。通过使用类型注解、枚举、可选链、空值合并运算符、泛型、接口、解构、异步/等待、函数式编程技术以及各种助手类型(如PickOmit和可辨识联合),你可以创建更健壮和可扩展的 TypeScript 应用程序。

这些技巧还可以帮助你及早捕获错误、提高代码的可读性并减少需要编写的样板代码量。借助 TypeScript 强大的类型系统和这些技巧,你可以编写更易于理解和长期维护的代码。


该文章在 2024/11/19 9:25:29 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2024 ClickSun All Rights Reserved