TypeScript从入门到进阶(万字长文)

1,159 阅读4分钟

第一部分:基础知识

1. 什么是TypeScript?

TypeScript是JavaScript的超集,主要增加了静态类型和一些面向对象编程的特性。TypeScript的代码最终会被编译为JavaScript,可以在任何支持JavaScript的环境中运行。

TypeScript的特点

  • 静态类型:可选的静态类型系统,可以在编译期间发现错误。
  • 编译时检查:提供更早的错误检测,减少运行时错误。
  • 面向对象:支持类、接口、继承等面向对象的编程范式。
  • 模块化:支持ES6模块,使代码结构更清晰。

2. TypeScript的安装

要在项目中使用TypeScript,首先需要安装TypeScript编译器。可以使用npm来安装:

npm install -g typescript

安装完成后,可以使用以下命令验证:

tsc -v

第二部分:TypeScript基础语法

1. 基本类型

TypeScript 支持多种基本数据类型,主要包括:

1.1 数字类型

let num: number = 42;

1.2 字符串类型

let str: string = "Hello TypeScript";

1.3 布尔类型

let isActive: boolean = true;

1.4 数组类型

let numbers: number[] = [1, 2, 3];
let strings: Array<string> = ["a", "b", "c"];

1.5 元组类型

元组是一种特殊的数组,能够指定各个元素的类型:

let tuple: [string, number] = ["Alice", 25];

1.6 枚举类型

enum Color {
    Red,
    Green,
    Blue
}
let c: Color = Color.Green;

1.7 Any 类型

any 类型表示可以是任意类型,适用于动态类型的情况:

let notSure: any = 4;
notSure = "Maybe a string instead";
notSure = false; // OK, definitely a boolean

1.8 Void 类型

void 通常用于表示函数没有返回值:

function greet(): void {
    console.log("Hello");
}

2. 函数

2.1 函数类型

定义函数类型时,可以指定参数和返回值的类型:

function add(x: number, y: number): number {
    return x + y;
}

2.2 可选参数与默认参数

在函数参数列表中,可以通过 ? 来标记可选参数,通过 = 来设定默认参数:

function multiply(x: number, y?: number): number {
    return y ? x * y : x;
}

function greet(name: string = "World"): string {
    return `Hello, ${name}!`;
}

2.3 剩余参数

使用 ... 语法来处理可变参数的情况:

function sum(...args: number[]): number {
    return args.reduce((a, b) => a + b, 0);
}

3. 类和接口

3.1 类

TypeScript 的类语法与 ES6 类语法基本一致,支持继承和修饰符(如 public, private, protected):

class Animal {
    private name: string;

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

    public getName(): string {
        return this.name;
    }
}

class Dog extends Animal {
    bark() {
        console.log("Woof!");
    }
}

3.2 接口

接口用于定义对象的结构,支持类型检查:

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

const john: Person = {
    name: "John",
    age: 30
};

3.3 接口与类的实现

一个类可以实现多个接口,来保证自身能够实现所需的方法:

interface Flyer {
    fly(): void;
}

class Bird implements Flyer {
    fly() {
        console.log("Flying");
    }
}

3.4 继承接口

接口支持继承:

interface Animal {
    name: string;
}

interface Dog extends Animal {
    bark(): void;
}

4. 泛型

泛型使得函数和类可以支持多种数据类型,增加了代码的复用性。

4.1 泛型函数

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

let output1 = identity<string>("myString");
let output2 = identity<number>(100);

4.2 泛型类

class Pair<K, V> {
    constructor(public key: K, public value: V) {}
}

let pair = new Pair<string, number>("age", 30);

5. 模块

TypeScript 的模块系统允许将代码分成多个文件。可以使用 exportimport 定义模块关系。

5.1 导出与导入

// module.ts
export class Car {
    drive() {
        console.log("Driving");
    }
}

// app.ts
import { Car } from './module';
const myCar = new Car();
myCar.drive();

5.2 默认导出

export default 用于导出一个默认模块:

// defaultModule.ts
export default class DefaultCar {
    drive() {
        console.log("Driving default car");
    }
}

// app.ts
import DefaultCar from './defaultModule';
const myDefaultCar = new DefaultCar();
myDefaultCar.drive();

6. 装饰器

装饰器是 TypeScript 的一个实验性特性,允许在类和类的方法上增加额外的功能。

6.1 类装饰器

function log(target: Function) {
    console.log(`Class ${target.name} is created`);
}

@log
class Person {
    constructor(public name: string) {}
}

6.2 方法装饰器

function logMethod(target: any, propertyName: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    descriptor.value = function (...args: any[]) {
        console.log(`Method ${propertyName} was called with args: ${args}`);
        return originalMethod.apply(this, args);
    };
}

class Calculator {
    @logMethod
    add(x: number, y: number) {
        return x + y;
    }
}

第三部分:进阶特性

1. 高级类型

1.1 联合类型

可以使用联合类型来定义一个变量可以是多种类型:

let value: string | number;
value = "Hello";
value = 42;

1.2 交叉类型

交叉类型可以组合多个类型,生成一个新类型:

interface A {
  a: number;
}

interface B {
  b: string;
}

const ab: A & B = { a: 1, b: "hello" };

1.3 类型别名

可以使用type关键字创建类型别名:

type ID = string | number;

2. 类型推断

TypeScript会根据上下文自动推导变量类型,无需显式声明:

let num = 5; // TypeScript推断为number

3. 类型断言

在某些情况下,TypeScript可能无法推断出正确的类型,可以使用类型断言:

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

4. 装饰器

装饰器是TypeScript特有的,用于装饰类、方法或属性的元编程:

function log(target: any, propertyName: string, descriptor: PropertyDescriptor) {
  console.log(`Method ${propertyName} was called`);
}

class Math {
  @log
  add(x: number, y: number): number {
    return x + y;
  }
}

5. 模块化

TypeScript支持ES6模块,可以使用importexport来管理模块依赖。

// module.ts
export const PI = 3.14;
export function circleArea(radius: number): number {
  return PI * radius * radius;
}

// main.ts
import { PI, circleArea } from './module';

6. 异步编程

TypeScript可以原生支持Promise和async/await,处理异步操作更加简洁:

async function fetchData(): Promise<string> {
  const response = await fetch("https://api.example.com");
  return await response.text();
}

第三部分:项目实战

1. 创建TypeScript项目

在项目根目录下创建tsconfig.json文件,以配置TypeScript编译选项:

{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  }
}

2. 使用Node.js和TypeScript

TypeScript非常适合Node.js应用开发。可以将TypeScript文件与Node.js结合使用。

npm init -y
npm install express
npm install --save-dev typescript @types/node @types/express

创建一个简单的Express服务器:

// app.ts
import express from 'express';

const app = express();
const PORT = 3000;

app.get('/', (req, res) => {
  res.send('Hello TypeScript');
});

app.listen(PORT, () => {
  console.log(`Server is running on http://localhost:${PORT}`);
});

3. 使用TypeScript构建React项目

TypeScript与React结合使用可以提升开发体验,安装React和TypeScript:

npx create-react-app my-app --template typescript

在组件中使用TypeScript:

import React from 'react';

interface Props {
  title: string;
}

const MyComponent: React.FC<Props> = ({ title }) => {
  return <h1>{title}</h1>;
};

export default MyComponent;

4. 测试TypeScript应用

使用Jest进行TypeScript测试,需要安装Jest和ts-jest:

npm install --save-dev jest ts-jest @types/jest

创建jest.config.js配置文件:

module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
};

5. 编写测试用例

使用Jest编写测试用例:

// sum.ts
export const sum = (a: number, b: number): number => a + b;

// sum.test.ts
import { sum } from './sum';

test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});

6. 在CI/CD中使用TypeScript

可以在CI/CD流程中使用TypeScript进行构建和测试。常见的构建工具有Webpack、Gulp和Grunt。确保在流程中执行tsc命令来编译TypeScript代码。

第四部分:TypeScript最佳实践

1. 明确类型

尽量避免使用any类型,保持类型的明确性,以提高代码质量:

let value: any;  // 不推荐
let value: string;  // 推荐

2. 使用接口

使用接口定义对象可以提高代码的可读性和可维护性:

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

function getUser(user: User) {
  console.log(user.id, user.name);
}

3. 减少代码重复

通过函数和类的重用,来减少代码重复,提高可维护性:

class User {
  constructor(public id: number, public name: string) {}

  display() {
    console.log(this.id, this.name);
  }
}

4. 使用抽象类和接口

使用抽象类和接口来定义类的公共行为,提高代码结构的清晰度:

abstract class Shape {
  abstract area(): number;
}

class Circle extends Shape {
  constructor(private radius: number) {
    super();
  }
  
  area() {
    return Math.PI * this.radius ** 2;
  }
}

5. 细化类型定义

根据需求细化类型定义。例如,使用unionintersection类型结合具体业务逻辑进行定义。

type Callback = (value: string) => void;

function execute(value: string, callback: Callback): void {
  callback(value);
}

6. 保持代码风格一致

使用格式化工具如Prettier和Linting工具如ESLint保持代码风格一致,增强代码可读性:

npm install --save-dev eslint eslint-config-prettier eslint-plugin-prettier