TypeScript快速入门指南

61 阅读12分钟

副本_科技风智能家居宣传手机海报__2024-09-18+16_41_27.jpg 在这个数字化飞速发展的时代,Web开发技术正以前所未有的速度不断演进。无论你是专注于前端、后端,还是身兼数职的全栈开发者,紧跟这些技术的最新动态都是至关重要的。今天,我们想向大家介绍一款能让JavaScript焕发新生光彩的神奇工具——TypeScript。在接下来的文章中,将引导大家迅速掌握TypeScript的基础概念,不仅适合初学者入门,也希望能为经验丰富的开发者带来一些新颖的思考角度。

1)TypeScript简介

TypeScript 是 JavaScript 的一个超集,添加了静态类型系统和其他特性,如接口、枚举、泛型等。这些特性有助于在开发过程中捕获错误,并使代码更易于维护和理解。如下是一个简单的TypeScript写法小案例:

functionsalutation(name: string) {
return Hello, ${name}!;
}
console.log(greet("Alice"));

Tips: 借助TypeScript 来定义变量、函数等的类型,可以很大程度的提升代码的可靠性,并且提升代码可读性。**

适用场景:在需要类型安全的大型工程中,TypeScript 是较为理想的选择。

2)基础类型

TypeScript支持多种基础类型,包括数字(number)、字符串(string)、布尔值(boolean)、数组等,使得变量的定义更加清晰明确:

let age: number =30;

let name: string = "Bob";
let isStudent: boolean = true;
let numbers: number[] = [1, 2, 3];

Tips: 通过TypeScript 的类型判断,可以自动确定变量的类型,提升开发效率。

适用场景:适用于在开发中进行定义简单数据类型的场景。

3) 接口(Interfaces)

接口用于确保对象遵循特定的格式。

interface Person {

firstName: string;

lastName: string;

age?: number; // 可选属性

greet(otherPerson: Person): void; // 方法

}

let customer: Person = {

firstName: "Jane",

lastName: "Doe",

greet(otherPerson: Person) {

console.log(Hello, ${otherPerson.firstName} ${otherPerson.lastName}!);

}

};

customer.greet({ firstName: "Bob", lastName: "Smith" });

Tips: 接口用于帮助你在对象间强制实现一致的结构。

适用场景:适用于在开发中需要定义数据契约的场景。

4)类(Classes)

TypeScript的类让你能够利用面向对象编程思想,采取结构化的方式来模拟现实世界的实体。

class Animal {

name: string;

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

move(distanceInMeters: number = 0) {

console.log(${this.name} moved ${distanceInMeters}m.);

}

}

class Dog extends Animal {

bark() {

console.log(${this.name} says Woof!);

}

}

let myDog = new Dog("Mitzie");

myDog.bark();

myDog.move(10);

Tips: 可以利用public、private和protected等访问修饰符来实现更好的封装。

适用场景:适用于在开发中模拟现实世界中的实体。

5) 泛型(Generics)

泛型允许在定义函数、接口或类时,使用类型参数。从而可以创建适用于多种数据类型的可重用组件。

function identity(arg: T): T {
return arg;
}
let output = identity("hello");

Tips: 泛型有助于实现让一个函数或者类能够与任何数据类型一起工作。

适用场景:当希望一个函数或者类能够与任何数据类型一起工作时,使用泛型是一个很好的选择。

6) 枚举(Enums)

枚举用于定义一组命名的常量,通过这种方式可以使代码更加清晰易读。

enum Direction {
Up,
Down,
Left,
Right
}
let heading: Direction = Direction.Up;

Tips: 枚举通过为数字值赋予友好的名称,帮助使你的代码更易于阅读和理解。

适用场景:当你有一系列的相关常量时可以使用枚举,比如方向、状态码等。

7) 类型断言(Type Assertion)

在TypeScript无法推断变量类型时,类型断言明确告诉编译器变量的类型。可用于处理外部数据源的数据。

let input: any = "hello";
let length: number = (input as string).length;

Tips: 类型断言有助于处理外部数据源。

适用场景:当你在开发时对某个数据的了解超过TypeScript时,使用类型断言是一个很好的选择。

8) 装饰器(Decorators)

装饰器是一种特殊的声明,可以附加到类、方法、访问器、属性或参数上。另外,在Angular等框架中,装饰器广泛用于元数据反射。

function log(target: any, key: string) {
console.log(Method ${key} called);
}

class Example {
@log
someMethod() {
// 方法实现
}
}

Tips: 在Angular等开发框架中,装饰器广泛应用于元数据反射。

适用场景:当你在开发时需要向类及其成员添加元数据时,可使用装饰器。

9) 模块(Modules)

TypeScript中的模块帮助将代码组织成可重用的单元。利用模块可以保持代码库的整洁和可维护性。

// math.ts
export function add(a: number, b: number): number {
return a + b;
}

// app.ts
import { add } from './math';
console.log(add(2, 3)); // 输出: 5

Tips: 合适的模块能够提升你的代码质量。

适用场景:对于构建大型应用结构至关重要。

10) 命名空间(Namespaces)

命名空间为通过分组逻辑相关的对象来组织代码:

namespace Geometry {
export class Circle {
// Circle类的实现
}
}

let circle = new Geometry.Circle();

虽然在现代JavaScript和TypeScript开发中,模块已经成为组织代码的首选方式。然而,在某些特定场景下,命名空间仍然非常有用,特别是在将现有的大型代码库迁移到TypeScript时。

11) 类型推断(Type Inference)

TypeScript的类型推断能力意味着即使在未显式指定类型的情况下,编译器也能自动确定变量的类型:

let num = 10; // TypeScript推断出类型为number

Tips: TypeScript的类型断言能够节省时间,使代码更为清晰。

适用场景:在编写简洁代码时,不希望牺牲类型安全的情况下,可以使用类型断言。

12) 类型守卫(Type Guards)

类型守卫允许你在条件块内缩小变量的类型范围,可用于处理联合类型,即复杂或动态类型。

function isNumber(x: any): x is number {
return typeof x === "number";
}

if (isNumber(value)) {
// 在这个块里,TypeScript知道'value'是一个数字
}

Tips: TypeScript的类型在处理联合类型时特别有帮助。

适用场景:在开发时处理较为复杂或者动态的数据类型时,可使用类型守卫。

13) 联合类型(Union Types)

联合类型允许一个变量具有多种类型。

let result: number | string;
result = 10; // 有效
result = "error"; // 也有效

Tips: TypeScript的联合类型可用于处理变量不同的场景。

适用场景:适用于表示多样化的数据类型。

14) 交叉类型(Intersection Types)

交叉类型允许将多种类型组合成一个类型。

type A = { a: number };
type B = { b: string };
type C = A & B; // C同时拥有number类型的属性和string类型的属性

Tips: 用于组合不同类型,处理复杂场景。

适用场景:适用于创建复杂的数据结构。

15) 类型别名(Type Aliases)

类型别名可用于为任何数据类型创建一个名称,可用于为复杂的类型提供描述性名称,从而提高代码的可读性和可维护性。

type Age = number;
let userAge: Age = 25;

Tips: 使用类型别名为复杂的类型提供描述性名称。

适用场景:适用于复杂的数据类型。

16) 三斜线指令(Triple-Slash Directives)

三斜线指令是包含单个XML标签的单行注释,常用于声明文件间的依赖关系,有助于模块和声明文件的工作。

///

Tips: 在处理模块和声明文件时非常有用。

适用场景:三斜线指令通常用于声明文件之间的依赖,有助于模块和声明文件的工作。

17) 对JavaScript文件的类型检查

TypeScript不仅可以用来编写TypeScript代码,还可以用于检查和类型检查JavaScript文件,从而捕获bug并提升代码质量,常用于将JavaScript代码库迁移到TypeScript的项目中。

// @ts-check
let num: number = "not a number"; // TypeScript会抛出类型错误

Tips: 通过类型检查提升代码质量以及开发效率。

适用场景:适用于将JavaScript代码库迁移到TypeScript的项目场景。

18) 解构对象的类型推断

TypeScript能够为解构的对象推断出类型。

let person = { name: "Alice", age: 30 };
let { name, age } = person; // TypeScript推断出'name'和'age'的类型

Tips: 解构对象的类型推断能节省时间,减少冗余。

适用场景:适用于处理复杂的数据结构。

19) 条件类型(Conditional Types)

TypeScript中的条件类型允许你创建依赖于其他类型的类型。

type NonNullable = T extends null | undefined ? never : T;
type StringOrNumber = string | number;
type NonNullableStringOrNumber = NonNullable; // 结果: string | number

Tips: 条件类型对于创建灵活和条件依赖的类型定义非常强大。

适用场景:对于创建依赖于条件的泛型类型非常有用。

20) 映射类型(Mapped Types)

TypeScript的映射类型允许从现有类型创建新类型。

type Flags = {
option1: boolean;
option2: boolean;
};
type NullableFlags = { [K in keyof Flags]: Flags[K] | null }; // 结果: { option1: boolean | null, option2: boolean | null }

Tips: 当你将现有类型转换为新类型时可以使用映射类型。

适用场景:在创建现有类型的变体时非常有帮助。

21) 声明合并(Declaration Merging)

在TypeScript中,声明合并允许为同一个实体合并多个声明。

interface User {
name: string;
}
interface User {
age: number;
}
let newUser: User = { name: "Alice", age: 30 };

Tips: 合并声明对于扩展现有类型非常有用,且不需要直接修改它们。

适用场景:合并声明可用于对第三方库添加功能的场景。

22) 类型守卫与类(Type Guards with Classes)

类型守卫也可以用于类,从而缩小实例的类型范围。

class Animal {
move() {
console.log("Moving...");
}
}
class Dog extends Animal {
bark() {
console.log("Woof!");
}
}
function isDog(animal: Animal): animal is Dog {
return (animal as Dog).bark !== undefined;
}

Tips: 在处理继承和多态性时非常有效。

适用场景:可用于处理多态性行为。

23) 元组类型(Tuple Types)

TypeScript的元组类型允许表达一个数组,其中固定数量的元素的类型是已知的。

let coordinates: [number, number] = [10, 20];

Tips: 在处理已知元素类型的固定长度数组时使用元组类型。

适用场景:在表示结构化数据,如坐标、RGB值等可使用元组类型。

24) 索引签名(Index Signatures)

索引签名允许定义对象如何被索引。

interface StringArray {
[index: number]: string;
}
let myArray: StringArray = ["a", "b", "c"];

Tips: 用于处理表现得像数组的对象。

适用场景:适用于动态的数据类型。

25) 使用typeof和instanceof的类型守卫(Type Guards with typeof and instanceof)

可以使用typeof和instanceof操作符创建类型守卫。

function logValue(value: string | number) {
if (typeof value === "string") {
console.log(value.toUpperCase());
} else if (value instanceof Number) {
console.log(value.valueOf());
}
}

Tips: 注意,typeof用于检查原始类型,instanceof是用来检查类的实例。

适用场景:适用于在条件块中检查特定类型的数据。

26) 递归类型(Recursive Types)

TypeScript支持定义递归类型,即一个类型可以引用它自身。

interface TreeNode {
value: string;
children: TreeNode[];
}

Tips:递归类型对于表示层级的数据结构非常有用。

适用场景:适合模拟树形数据,如文件系统的目录结构。

27) 字符串字面量类型(String Literal Types)

字符串字面量类型允许定义一个类型,它只能有特定的字符串值。

type Direction = "up" | "down" | "left" | "right";
let move: Direction = "up";

Tips:字符串字面量类型有助于创建具体和简洁的类型定义。

适用场景:可用于表示一组固定的字符串值,如命令、方向等。

28) 命名空间合并(Namespace Merging)

命名空间合并允许在多个文件中扩展现有的命名空间,用于为现有命名空间添加功能。

// math.ts
namespace Math {
export function subtract(a: number, b: number): number {
return a - b;
}
}
// extendedMath.ts
namespace Math {
export function multiply(a: number, b: number): number {
return a * b;
}
}

Tips:命名空间能够帮助在多个文件中模块化代码。

适用场景:适用于模块化工程。

29) 类型谓词(Type Predicates)

类型谓词是返回类型谓词的函数,用于在条件块内缩小类型范围:

function isString(value: any): value is string {
return typeof value === "string";
}
if (isString(input)) {
console.log(input.toUpperCase());
}

Tips:类型谓词可用于创建可重用的类型缩小函数非常有用。

适用场景:适用于处理复杂的类型检查。

30) 类型推断和严格模式(Inference and Strict Mode)

TypeScript的严格模式启用额外的类型检查选项,以捕获更多错误,从而提升代码质量。

// @ts-check
let num: number = "not a number"; // 在严格模式下,TypeScript会抛出类型错误

Tips:类型推断与严格模式检查对于开发者来说是必不可少的,能够帮助开发者捕获更多潜在的类型错误。

适用场景:对于希望增强类型安全和避免潜在错误的项目非常有用。

31) 使用in操作符的类型守卫

可以使用in操作符创建类型守卫,以检查对象中是否存在某个属性:

function hasName(obj: any): obj is { name: string } {
return "name" in obj;
}
if (hasName(user)) {
console.log(user.name);
}

Tips:in操作符主要用于动态检查属性存在性。

适用场景:在类型安全的方式下检查对象属性时非常有帮助。

32) 数组的类型推断

TypeScript能够基于分配给它们的元素推断数组的类型。

let numbers = [1, 2, 3]; // TypeScript推断'numbers'为number[]

Tips:数组的类型推断可以很好的简化代码并提升代码的可读性。

适用场景:用于处理已知元素的数组。

33) Promise和异步/等待(Async/Await)

TypeScript支持Promise和async/await语法,用于处理异步操作

function fetchData(): Promise {
return new Promise(resolve => {
setTimeout(() => {
resolve("Data fetched!");
}, 2000);
});
}
async function fetchDataAsync() {
const data = await fetchData();
console.log(data);
}

Tips:Promise和async/await对于以同步方式处理异步代码至关重要。

适用场景:适用于在以可读的方式管理异步操作时。

34) 泛型约束(Generics Constraints)

泛型约束允许限制可以用于泛型类型参数的类型,确保类型安全,并向TypeScript提供了更具体的信息。

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

Tips:通过泛型约束,我们可以保障类型的安全性,同时为TypeScript提供更加精确的信息。

适用场景:在处理泛型类型时,采用泛型约束将会极大地受益于这一特性。

35) 默认值的类型推断

TypeScript可以基于变量的默认值推断类型,对于初始化变量而不显式指定类型非常方便。

let message = "Hello, World!"; // TypeScript推断'message'为string

Tips:利用默认值的类型推断能便捷地初始化变量,无需明确指定其类型。最佳适用场景:此功能可缩减代码长度,使TypeScript能够根据初始值自动推断变量类型。

结束

在这次探索之旅中,我们共同挖掘了TypeScript的深厚潜力,从基础类型体系延伸至高级复杂技巧,它无疑引领我们迈入了一个编程的新纪元。不论你是编程新手还是经验丰富的开发者,TypeScript都以其强大的功能和机制,助力我们以更稳健、更高效的途径去开发应用程序。

借由这一系列文章,我们期望你能领略到TypeScript的独特魅力,以及它如何助你提升代码的品质与可维护性。请铭记,学习新技术之路虽充满挑战,但只要你持之以恒地探索与实践,这些挑战终将成为你宝贵的技能财富与丰富经验。


标题下的动画.gif