一、TypeScript基础概念

1.1 什么是TypeScript?

TypeScript是JavaScript的超集,由微软开发,在JavaScript的基础上添加了静态类型系统。它可以在编译时捕获错误,提高代码的可维护性和开发效率。

1.2 TypeScript的历史

  • 2012年:微软发布TypeScript 0.8版本
  • 2013年:TypeScript 1.0发布,支持类型推断
  • 2014年:TypeScript 1.1发布,性能大幅提升
  • 2016年:TypeScript 2.0发布,引入不可空类型
  • 2018年:TypeScript 3.0发布,支持项目引用
  • 2020年:TypeScript 4.0发布,引入更多高级特性
  • 至今:持续快速发展,版本迭代到5.x

1.3 TypeScript的优势

  • 静态类型检查:在编译时发现错误,减少运行时错误
  • 更好的IDE支持:自动补全、类型提示、重构功能
  • 代码可读性:类型注解让代码更易理解
  • 更好的维护性:大型项目更易于维护和重构
  • 面向对象编程:完整的类、接口、抽象类支持
  • 现代JavaScript特性:支持最新的ECMAScript特性
  • 渐进式采用:可以逐步从JavaScript迁移

1.4 TypeScript与JavaScript的关系

// TypeScript是JavaScript的超集
// 所有有效的JavaScript代码都是有效的TypeScript代码

// JavaScript代码
function greet(name) {
    return 'Hello, ' + name;
}

// TypeScript代码(完全兼容JavaScript)
function greet(name: string): string {
    return 'Hello, ' + name;
}

二、TypeScript安装和配置

2.1 安装TypeScript

# 全局安装
npm install -g typescript

# 局部安装(推荐)
npm install --save-dev typescript

# 验证安装
tsc --version

2.2 创建第一个TypeScript项目

# 创建项目目录
mkdir my-typescript-app
cd my-typescript-app

# 初始化项目
npm init -y

# 安装TypeScript
npm install --save-dev typescript

# 创建TypeScript文件
touch hello.ts
// hello.ts
const message: string = 'Hello, TypeScript!';
console.log(message);
# 编译TypeScript文件
tsc hello.ts

# 运行编译后的JavaScript文件
node hello.js

2.3 tsconfig.json配置文件

{
  "compilerOptions": {
    /* 基本选项 */
    "target": "ES2020",                    // 编译目标
    "module": "commonjs",                  // 模块系统
    "lib": ["ES2020", "DOM"],              // 包含的库文件
    "outDir": "./dist",                    // 输出目录
    "rootDir": "./src",                    // 源代码目录
    "removeComments": true,                // 删除注释
    "strict": true,                        // 启用所有严格类型检查选项
    
    /* 额外检查 */
    "noUnusedLocals": true,                // 检查未使用的局部变量
    "noUnusedParameters": true,            // 检查未使用的参数
    "noImplicitReturns": true,             // 检查函数是否有返回值
    "noFallthroughCasesInSwitch": true,    // 防止switch语句穿透
    
    /* 模块解析选项 */
    "moduleResolution": "node",            // 模块解析策略
    "baseUrl": "./",                       // 基础路径
    "paths": {                             // 路径映射
      "@/*": ["src/*"]
    },
    "esModuleInterop": true,               // 启用ES模块互操作
    "allowSyntheticDefaultImports": true,  // 允许合成默认导入
    
    /* 高级选项 */
    "skipLibCheck": true,                  // 跳过库文件的类型检查
    "forceConsistentCasingInFileNames": true, // 强制文件名大小写一致
    
    /* 源映射 */
    "sourceMap": true,                     // 生成source map文件
    "declaration": true,                   // 生成声明文件
    "declarationMap": true                 // 生成声明文件source map
  },
  "include": [
    "src/**/*"
  ],
  "exclude": [
    "node_modules",
    "dist"
  ]
}

2.4 编译选项详解

# 监听模式
tsc --watch

# 只编译错误不生成文件
tsc --noEmit

# 删除生成的文件
tsc --clean

# 显示详细错误信息
tsc --pretty false

# 指定配置文件
tsc --project tsconfig.json

# 编译单个文件
tsc hello.ts

# 编译整个目录
tsc src

三、TypeScript基础类型

3.1 基本类型

// 布尔值
let isDone: boolean = false;
let isActive: boolean = true;

// 数字
let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;
let big: bigint = 100n;

// 字符串
let color: string = "blue";
let fullName: string = `Bob Smith`;
let age: number = 37;
let sentence: string = `Hello, my name is ${fullName}. I'll be ${age + 1} years old next month.`;

// 数组
let list1: number[] = [1, 2, 3];
let list2: Array<number> = [1, 2, 3];

// 元组
let x: [string, number];
x = ["hello", 10]; // 正确
x = [10, "hello"]; // 错误

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

enum Color {Red = 1, Green = 2, Blue = 4}
let colorName: string = Color[2]; // 显示'Green'

// Any(任意类型)
let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean

// Unknown(类型安全的any)
let userInput: unknown;
let userName: string;

userInput = 5;
userInput = "Max";

if (typeof userInput === "string") {
    userName = userInput; // 类型安全
}

// Void(没有任何类型)
function warnUser(): void {
    console.log("This is a warning message");
}

// Null和Undefined
let u: undefined = undefined;
let n: null = null;

// Never(永不存在的类型)
function error(message: string): never {
    throw new Error(message);
}

// Object
let obj: object = { name: "张三", age: 25 };

3.2 类型注解

// 变量类型注解
let name: string = "张三";
let age: number = 25;
let isStudent: boolean = true;

// 函数类型注解
function add(a: number, b: number): number {
    return a + b;
}

// 箭头函数类型注解
const multiply = (a: number, b: number): number => {
    return a * b;
};

// 可选参数
function greet(name: string, greeting?: string): string {
    return greeting ? `${greeting}, ${name}` : `Hello, ${name}`;
}

// 默认参数
function greetWithDefault(name: string, greeting: string = "Hello"): string {
    return `${greeting}, ${name}`;
}

// 剩余参数
function sumAll(...numbers: number[]): number {
    return numbers.reduce((acc, num) => acc + num, 0);
}

// 对象类型注解
let user: { name: string; age: number } = {
    name: "张三",
    age: 25
};

// 可选属性
let person: { name: string; age?: number } = {
    name: "李四"
};

// 只读属性
let point: { readonly x: number; readonly y: number } = {
    x: 10,
    y: 20
};
// point.x = 5; // 错误:不能修改只读属性

// 函数类型
let myAdd: (x: number, y: number) => number = function(
    x: number,
    y: number
): number {
    return x + y;
};

四、接口(Interface)

4.1 基本接口

// 定义接口
interface Person {
    name: string;
    age: number;
}

// 使用接口
let user: Person = {
    name: "张三",
    age: 25
};

// 函数参数使用接口
function greet(person: Person): void {
    console.log(`Hello, ${person.name}!`);
}

4.2 可选属性

interface Car {
    brand: string;
    model: string;
    year?: number; // 可选属性
}

let myCar: Car = {
    brand: "Toyota",
    model: "Camry"
};

4.3 只读属性

interface Point {
    readonly x: number;
    readonly y: number;
}

let p1: Point = { x: 10, y: 20 };
// p1.x = 5; // 错误:不能修改只读属性

// ReadonlyArray
let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = a;
// ro[0] = 12; // 错误
// ro.push(5); // 错误
// ro.length = 100; // 错误
// a = ro; // 错误
a = ro as number[]; // 可以通过类型断言绕过

4.4 函数类型接口

interface SearchFunc {
    (source: string, subString: string): boolean;
}

let mySearch: SearchFunc = function(source: string, subString: string): boolean {
    let result = source.search(subString);
    return result > -1;
};

4.5 可索引类型

// 字符串索引签名
interface StringArray {
    [index: number]: string;
}

let myArray: StringArray = ["Bob", "Fred"];
let myStr: string = myArray[0];

// 数字索引签名
interface StringDictionary {
    [index: string]: string;
}

let myDict: StringDictionary = {
    firstName: "John",
    lastName: "Doe"
};

4.6 类类型接口

interface ClockInterface {
    currentTime: Date;
    setTime(d: Date): void;
}

class Clock implements ClockInterface {
    currentTime: Date = new Date();
    setTime(d: Date) {
        this.currentTime = d;
    }
    constructor(h: number, m: number) {}
}

4.7 接口继承

interface Shape {
    color: string;
}

interface Square extends Shape {
    sideLength: number;
}

let square: Square = {
    color: "red",
    sideLength: 10
};

// 多重继承
interface PenStroke {
    penWidth: number;
}

interface Square extends Shape, PenStroke {
    sideLength: number;
}

4.8 混合类型接口

interface Counter {
    (start: number): string;
    interval: number;
    reset(): void;
}

function getCounter(): Counter {
    let counter = (function(start: number) {} as unknown) as Counter;
    counter.interval = 123;
    counter.reset = function() {};
    return counter;
}

let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;

五、类型别名和联合类型

5.1 类型别名

// 基本类型别名
type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;
function getName(n: NameOrResolver): Name {
    if (typeof n === "string") {
        return n;
    } else {
        return n();
    }
}

// 对象类型别名
type User = {
    name: string;
    age: number;
};

let user: User = {
    name: "张三",
    age: 25
};

// 函数类型别名
type GreetFunction = (name: string) => void;
const greet: GreetFunction = (name: string) => {
    console.log(`Hello, ${name}!`);
};

5.2 联合类型

// 基本联合类型
let value: string | number;
value = "hello";
value = 123;

// 函数参数联合类型
function printId(id: number | string) {
    console.log(`Your ID is: ${id}`);
}

// 类型守卫
function printIdWithGuard(id: number | string) {
    if (typeof id === "string") {
        console.log(id.toUpperCase()); // id是string
    } else {
        console.log(id.toFixed(2)); // id是number
    }
}

5.3 交叉类型

interface BusinessPartner {
    name: string;
    credit: number;
}

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

type Employee = BusinessPartner & Identity;

let emp: Employee = {
    name: "张三",
    credit: 1000,
    id: 1
};

5.4 字面量类型

// 字符串字面量类型
type EventName = 'click' | 'dblclick' | 'mouseup' | 'mousedown';

function handleEvent(eventName: EventName) {
    // 处理事件
}

handleEvent('click'); // 正确
// handleEvent('dblclicks'); // 错误

// 数字字面量类型
type Dice = 1 | 2 | 3 | 4 | 5 | 6;
let diceRoll: Dice = 3;

// 布尔字面量类型
type Success = true;
type Failure = false;
type Result = Success | Failure;

六、类(Class)

6.1 基本类

class Person {
    // 属性
    name: string;
    age: number;

    // 构造函数
    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }

    // 方法
    greet(): void {
        console.log(`Hello, my name is ${this.name}`);
    }

    // Getter
    get info(): string {
        return `${this.name} is ${this.age} years old`;
    }

    // Setter
    set newName(name: string) {
        this.name = name;
    }
}

const person = new Person("张三", 25);
person.greet();
console.log(person.info);
person.newName = "李四";

6.2 继承

class Animal {
    name: string;

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

    move(distanceInMeters: number = 0) {
        console.log(`${this.name} moved ${distanceInMeters}m.`);
    }
}

class Snake extends Animal {
    constructor(name: string) {
        super(name);
    }

    move(distanceInMeters = 5) {
        console.log("Slithering...");
        super.move(distanceInMeters);
    }
}

class Horse extends Animal {
    constructor(name: string) {
        super(name);
    }

    move(distanceInMeters = 45) {
        console.log("Galloping...");
        super.move(distanceInMeters);
    }
}

let sam = new Snake("Sammy the Python");
let tom: Animal = new Horse("Tommy the Palomino");

sam.move();
tom.move(34);

6.3 访问修饰符

class Person {
    public name: string; // 默认为public
    private age: number; // 私有属性
    protected address: string; // 受保护属性
    readonly id: number; // 只读属性

    constructor(name: string, age: number, address: string, id: number) {
        this.name = name;
        this.age = age;
        this.address = address;
        this.id = id;
    }

    public greet(): void {
        console.log(`Hello, I'm ${this.name}`);
    }

    private getAge(): number {
        return this.age;
    }

    protected getAddress(): string {
        return this.address;
    }
}

class Employee extends Person {
    private salary: number;

    constructor(
        name: string,
        age: number,
        address: string,
        id: number,
        salary: number
    ) {
        super(name, age, address, id);
        this.salary = salary;
    }

    public getInfo(): string {
        // 可以访问protected属性
        return `${this.name}, ${this.address}, Salary: ${this.salary}`;
    }
}

6.4 静态属性和方法

class MathHelper {
    static PI: number = 3.14159;

    static calculateCircleArea(radius: number): number {
        return this.PI * radius * radius;
    }
}

console.log(MathHelper.PI); // 3.14159
console.log(MathHelper.calculateCircleArea(5)); // 78.53975

6.5 抽象类

abstract class Animal {
    abstract makeSound(): void;

    move(): void {
        console.log("moving...");
    }
}

class Dog extends Animal {
    makeSound(): void {
        console.log("Woof! Woof!");
    }
}

class Cat extends Animal {
    makeSound(): void {
        console.log("Meow!");
    }
}

const dog = new Dog();
dog.makeSound(); // "Woof! Woof!"
dog.move(); // "moving..."

const cat = new Cat();
cat.makeSound(); // "Meow!"
cat.move(); // "moving..."

七、泛型(Generics)

7.1 基本泛型

// 泛型函数
function identity<T>(arg: T): T {
    return arg;
}

let output1 = identity<string>("myString"); // 类型推断为string
let output2 = identity<number>(100); // 类型推断为number

// 泛型接口
interface GenericIdentityFn<T> {
    (arg: T): T;
}

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

let myIdentity: GenericIdentityFn<number> = identity;

7.2 泛型类

class GenericNumber<T> {
    zeroValue: T;
    add: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) {
    return x + y;
};

let stringNumeric = new GenericNumber<string>();
stringNumeric.zeroValue = "";
stringNumeric.add = function(x, y) {
    return x + y;
};

7.3 泛型约束

interface Lengthwise {
    length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length); // 现在我们可以访问length属性
    return arg;
}

loggingIdentity({ length: 10, value: 3 }); // 正确
// loggingIdentity(3); // 错误:number没有length属性

7.4 泛型接口

interface Box<T> {
    value: T;
}

let box: Box<string> = {
    value: "hello"
};

let numberBox: Box<number> = {
    value: 123
};

7.5 泛型类型别名

type Container<T> = { value: T };
type Tree<T> = {
    value: T;
    left: Tree<T> | null;
    right: Tree<T> | null;
};

八、装饰器(Decorators)

8.1 类装饰器

// 类装饰器
function sealed(constructor: Function) {
    Object.seal(constructor);
    Object.seal(constructor.prototype);
}

@sealed
class Greeter {
    greeting: string;
    constructor(message: string) {
        this.greeting = message;
    }
    greet() {
        return "Hello, " + this.greeting;
    }
}

8.2 方法装饰器

// 方法装饰器
function log(target: any, key: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    descriptor.value = function(...args: any[]) {
        console.log(`Calling ${key} with args:`, args);
        const result = originalMethod.apply(this, args);
        console.log(`${key} returned:`, result);
        return result;
    };
}

class Calculator {
    @log
    add(a: number, b: number): number {
        return a + b;
    }
}

const calc = new Calculator();
calc.add(2, 3);

8.3 属性装饰器

// 属性装饰器
function format(target: any, key: string) {
    let value = target[key];
    const getter = () => {
        return value;
    };
    const setter = (newVal: string) => {
        value = newVal.trim();
    };
    Object.defineProperty(target, key, {
        get: getter,
        set: setter,
        enumerable: true,
        configurable: true
    });
}

class Person {
    @format
    name: string;
    constructor(name: string) {
        this.name = name;
    }
}

const person = new Person("  张三  ");
console.log(person.name); // "张三"

8.4 参数装饰器

// 参数装饰器
function required(target: any, key: string, index: number) {
    console.log(`Required parameter at index ${index} in method ${key}`);
}

class Greeter {
    greet(@required name: string) {
        return "Hello " + name;
    }
}

九、模块系统

9.1 导出和导入

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

export function subtract(a: number, b: number): number {
    return a - b;
}

export const PI = 3.14159;

export interface User {
    name: string;
    age: number;
}

export class Calculator {
    add(a: number, b: number): number {
        return a + b;
    }
}

// 默认导出
export default function greet(name: string): string {
    return `Hello, ${name}!`;
}
// 导入
// main.ts
import greet from './utils'; // 默认导入
import { add, subtract, PI } from './utils'; // 命名导入
import { add as addition } from './utils'; // 重命名导入
import * as utils from './utils'; // 导入所有
import Calculator from './utils'; // 导入类

// 使用
greet("张三");
add(1, 2);
utils.subtract(3, 1);

9.2 模块解析

// 相对路径导入
import { add } from './utils';
import { subtract } from '../math/utils';

// 绝对路径导入
import { greet } from 'lodash';

// 使用@types类型定义
import { User } from 'lodash';

十、高级类型

10.1 类型推断

// 变量类型推断
let x = 3; // 推断为number
let y = "hello"; // 推断为string

// 函数返回类型推断
function add(a: number, b: number) {
    return a + b; // 推断返回类型为number
}

// 最佳通用类型推断
let zoo = [new Rhino(), new Elephant(), new Snake()];
// 推断为(Rhino | Elephant | Snake)[]

10.2 类型断言

// 尖括号语法
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;

// as语法(JSX中必须使用)
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;

// 类型断言的使用场景
interface User {
    name: string;
    age: number;
}

let user: any = { name: "张三", age: 25 };
let typedUser = user as User;

10.3 类型守卫

// typeof类型守卫
function padLeft(value: string, padding: string | number) {
    if (typeof padding === "number") {
        return Array(padding + 1).join(" ") + value;
    }
    if (typeof padding === "string") {
        return padding + value;
    }
    throw new Error(`Expected string or number, got '${padding}'.`);
}

// instanceof类型守卫
interface Padder {
    getPaddingString(): string;
}

class SpaceRepeatingPadder implements Padder {
    constructor(private spaces: number) {}
    getPaddingString() {
        return Array(this.spaces + 1).join(" ");
    }
}

class StringPadder implements Padder {
    constructor(private value: string) {}
    getPaddingString() {
        return this.value;
    }
}

function getRandomPadder() {
    return Math.random() < 0.5
        ? new SpaceRepeatingPadder(4)
        : new StringPadder("  ");
}

let padder: Padder = getRandomPadder();
if (padder instanceof SpaceRepeatingPadder) {
    padder; // 类型是SpaceRepeatingPadder
}
if (padder instanceof StringPadder) {
    padder; // 类型是StringPadder
}

10.4 空值合并和可选链

// 空值合并运算符
const foo = null ?? 'default string';
console.log(foo); // 'default string'

const baz = 0 ?? 42;
console.log(baz); // 0

// 可选链
interface User {
    name: string;
    address?: {
        city: string;
        street: string;
    };
}

const user: User = { name: "张三" };

const city = user?.address?.city; // undefined
const street = user?.address?.street; // undefined

10.5 条件类型

// 基本条件类型
type MessageOf<T> = T extends { message: unknown } ? T['message'] : never;

interface Email {
    message: string;
}

interface Dog {
    bark(): void;
}

type EmailMessageContents = MessageOf<Email>;
// string

type DogMessageContents = MessageOf<Dog>;
// never

// 条件类型约束
type Flatten<T> = T extends any[] ? T[number] : T;

type Str = Flatten<string[]>; // string
type Num = Flatten<number>; // number

10.6 映射类型

// 基本映射类型
type Readonly<T> = {
    readonly [P in keyof T]: T[P];
};

type Partial<T> = {
    [P in keyof T]?: T[P];
};

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

type ReadonlyUser = Readonly<User>;
type PartialUser = Partial<User>;

// 高级映射类型
type Getters<T> = {
    [P in keyof T as `get${Capitalize<string & P>}`]: () => T[P];
};

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

type LazyPerson = Getters<Person>;
// {
//   getName: () => string;
//   getAge: () => number;
// }

10.7 内置工具类型

// Partial<T> - 将所有属性变为可选
interface User {
    name: string;
    age: number;
}
type PartialUser = Partial<User>;

// Required<T> - 将所有属性变为必需
type RequiredUser = Required<PartialUser>;

// Readonly<T> - 将所有属性变为只读
type ReadonlyUser = Readonly<User>;

// Pick<T, K> - 选择特定属性
type NameAndAge = Pick<User, "name" | "age">;

// Omit<T, K> - 排除特定属性
type NameOnly = Omit<User, "age">;

// Record<K, T> - 创建对象类型
type UserRecord = Record<string, User>;

// Exclude<T, U> - 从类型中排除
type T1 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"

// Extract<T, U> - 从类型中提取
type T2 = Extract<"a" | "b" | "c", "a" | "f">; // "a"

// NonNullable<T> - 排除null和undefined
type T3 = NonNullable<string | null | undefined>; // string

// ReturnType<T> - 获取函数返回类型
type T4 = ReturnType<() => string>; // string

// Parameters<T> - 获取函数参数类型
type T5 = Parameters<(x: number, y: number) => void>; // [number, number]

十一、TypeScript与JavaScript的区别

11.1 主要区别对比

特性 JavaScript TypeScript
类型系统 动态类型 静态类型
编译 直接执行 需要编译为JavaScript
类型检查 运行时检查 编译时检查
IDE支持 基础支持 完整支持(智能提示、重构)
错误发现 运行时 编译时
面向对象 原型继承 类、接口、抽象类
代码可读性 需要注释 类型注解提高可读性
学习曲线 平缓 陡峭
文件扩展名 .js .ts
泛型 不支持 支持
装饰器 不支持 支持
命名空间 不支持 支持

11.2 代码对比示例

JavaScript代码
// user.js
function createUser(name, age) {
    return {
        name: name,
        age: age,
        greet: function() {
            console.log('Hello, ' + this.name);
        }
    };
}

const user = createUser('张三', 25);
user.greet();

// 可能的运行时错误
user.greet(); // 正确
user.age.toUpperCase(); // 运行时错误:user.age是数字,没有toUpperCase方法
TypeScript代码
// user.ts
interface User {
    name: string;
    age: number;
    greet(): void;
}

function createUser(name: string, age: number): User {
    return {
        name: name,
        age: age,
        greet: function() {
            console.log('Hello, ' + this.name);
        }
    };
}

const user: User = createUser('张三', 25);
user.greet();

// 编译时就能发现错误
// user.age.toUpperCase(); // 编译错误:类型'number'上不存在属性'toUpperCase'

11.3 函数对比

// JavaScript
function add(a, b) {
    return a + b;
}

add(1, 2); // 3
add('1', '2'); // '12'
add([1], [2]); // '1,2'
// TypeScript
function add(a: number, b: number): number {
    return a + b;
}

add(1, 2); // 3
// add('1', '2'); // 编译错误:类型'string'的参数不能赋给类型'number'的参数
// add([1], [2]); // 编译错误:类型'number[]'的参数不能赋给类型'number'的参数

11.4 对象对比

// JavaScript
const user = {
    name: '张三',
    age: 25
};

console.log(user.name); // '张三'
console.log(user.address); // undefined
// TypeScript
interface User {
    name: string;
    age: number;
    address?: string; // 可选属性
}

const user: User = {
    name: '张三',
    age: 25
};

console.log(user.name); // '张三'
console.log(user.address); // undefined,但有类型检查

// const invalidUser: User = { name: '李四' };
// 编译错误:类型'{ name: string; }'中缺少属性'age'

11.5 数组对比

// JavaScript
const numbers = [1, 2, 3];
const mixed = [1, 'hello', true];

numbers.push(4);
mixed.push({ name: 'object' }); // 可以添加任何类型
// TypeScript
const numbers: number[] = [1, 2, 3];
const mixed: (number | string | boolean)[] = [1, 'hello', true];

numbers.push(4);
// numbers.push('5'); // 编译错误:类型'string'的参数不能赋给类型'number'的参数

// mixed.push({ name: 'object' }); // 编译错误:类型'{ name: string; }'不能赋给类型'number | string | boolean'

十二、TypeScript最佳实践

12.1 配置最佳实践

{
  "compilerOptions": {
    "strict": true, // 启用严格模式
    "noImplicitAny": true, // 禁止隐式any
    "strictNullChecks": true, // 严格null检查
    "strictFunctionTypes": true, // 严格函数类型
    "noUnusedLocals": true, // 检查未使用的局部变量
    "noUnusedParameters": true, // 检查未使用的参数
    "noImplicitReturns": true, // 检查函数返回值
    "esModuleInterop": true, // ES模块互操作
    "skipLibCheck": true // 跳过库文件检查
  }
}

12.2 代码组织最佳实践

// 使用接口定义数据结构
interface User {
    id: number;
    name: string;
    email: string;
    createdAt: Date;
}

// 使用类型别名定义联合类型
type Status = 'pending' | 'active' | 'completed';

// 使用枚举定义常量
enum Role {
    ADMIN = 'admin',
    USER = 'user',
    GUEST = 'guest'
}

// 模块化导出
export { User, Status, Role };

// 使用命名空间组织相关功能
namespace Auth {
    export function login(username: string, password: string): void {
        // 登录逻辑
    }

    export function logout(): void {
        // 登出逻辑
    }
}

12.3 类型定义最佳实践

// 1. 优先使用interface定义对象类型
interface Person {
    name: string;
    age: number;
}

// 2. 使用type定义联合类型、交叉类型
type StringOrNumber = string | number;

// 3. 避免使用any,使用unknown代替
function processData(data: unknown) {
    if (typeof data === 'string') {
        console.log(data.toUpperCase());
    }
}

// 4. 使用readonly定义不可变数据
interface Config {
    readonly apiUrl: string;
    readonly timeout: number;
}

// 5. 使用泛型提高代码复用性
function first<T>(arr: T[]): T | undefined {
    return arr[0];
}

12.4 错误处理最佳实践

// 使用类型守卫进行类型检查
function isString(value: unknown): value is string {
    return typeof value === 'string';
}

function processValue(value: unknown) {
    if (isString(value)) {
        console.log(value.toUpperCase());
    } else {
        console.log('Not a string');
    }
}

// 使用错误类型
class ValidationError extends Error {
    constructor(public field: string, message: string) {
        super(message);
        this.name = 'ValidationError';
    }
}

function validateEmail(email: string): void {
    if (!email.includes('@')) {
        throw new ValidationError('email', 'Invalid email format');
    }
}

// 使用Result类型处理可能失败的操作
type Result<T, E = Error> = {
    success: true;
    value: T;
} | {
    success: false;
    error: E;
};

function safeParseJSON(json: string): Result<object> {
    try {
        return {
            success: true,
            value: JSON.parse(json)
        };
    } catch (error) {
        return {
            success: false,
            error: error as Error
        };
    }
}

十三、实战项目:TypeScript + Express

13.1 项目初始化

# 创建项目目录
mkdir ts-express-app
cd ts-express-app

# 初始化项目
npm init -y

# 安装依赖
npm install express
npm install --save-dev typescript @types/express @types/node ts-node nodemon

# 创建配置文件
touch tsconfig.json

13.2 tsconfig.json

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "lib": ["ES2020"],
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

13.3 用户模型和类型定义

// src/types/user.types.ts
export interface User {
    id: number;
    name: string;
    email: string;
    age: number;
    createdAt: Date;
    updatedAt: Date;
}

export interface CreateUserDto {
    name: string;
    email: string;
    age: number;
}

export interface UpdateUserDto {
    name?: string;
    email?: string;
    age?: number;
}

export interface ErrorResponse {
    message: string;
    errors?: Record<string, string[]>;
}

13.4 验证中间件

// src/middleware/validation.middleware.ts
import { Request, Response, NextFunction } from 'express';

export const validate = (
    schema: Record<string, any>
) => {
    return (req: Request, res: Response, next: NextFunction) => {
        const errors: Record<string, string[]> = {};

        for (const [field, rules] of Object.entries(schema)) {
            const value = req.body[field];
            
            if (rules.required && (value === undefined || value === null)) {
                if (!errors[field]) errors[field] = [];
                errors[field].push(`${field} is required`);
                continue;
            }

            if (rules.type && value !== undefined && typeof value !== rules.type) {
                if (!errors[field]) errors[field] = [];
                errors[field].push(`${field} must be a ${rules.type}`);
            }

            if (rules.min !== undefined && value !== undefined && value < rules.min) {
                if (!errors[field]) errors[field] = [];
                errors[field].push(`${field} must be at least ${rules.min}`);
            }

            if (rules.email && value !== undefined) {
                const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
                if (!emailRegex.test(value)) {
                    if (!errors[field]) errors[field] = [];
                    errors[field].push(`${field} must be a valid email`);
                }
            }
        }

        if (Object.keys(errors).length > 0) {
            return res.status(400).json({
                message: 'Validation failed',
                errors
            });
        }

        next();
    };
};

13.5 错误处理中间件

// src/middleware/error.middleware.ts
import { Request, Response, NextFunction } from 'express';
import { ErrorResponse } from '../types/user.types';

export const errorHandler = (
    error: Error,
    req: Request,
    res: Response<ErrorResponse>,
    next: NextFunction
) => {
    console.error('Error:', error);

    res.status(500).json({
        message: error.message || 'Internal server error'
    });
};

export const notFoundHandler = (
    req: Request,
    res: Response<ErrorResponse>
) => {
    res.status(404).json({
        message: `Route ${req.method} ${req.url} not found`
    });
};

13.6 用户控制器

// src/controllers/user.controller.ts
import { Request, Response } from 'express';
import { User, CreateUserDto, UpdateUserDto } from '../types/user.types';

// 模拟数据库
let users: User[] = [
    {
        id: 1,
        name: '张三',
        email: 'zhangsan@example.com',
        age: 25,
        createdAt: new Date(),
        updatedAt: new Date()
    },
    {
        id: 2,
        name: '李四',
        email: 'lisi@example.com',
        age: 30,
        createdAt: new Date(),
        updatedAt: new Date()
    }
];

let nextId = 3;

export const getAllUsers = (req: Request, res: Response<User[]>) => {
    res.json(users);
};

export const getUserById = (req: Request<{ id: string }>, res: Response<User | { message: string }>) => {
    const id = parseInt(req.params.id);
    const user = users.find(u => u.id === id);
    
    if (!user) {
        return res.status(404).json({ message: 'User not found' });
    }
    
    res.json(user);
};

export const createUser = (req: Request<{}, User, CreateUserDto>, res: Response<User>) => {
    const newUser: User = {
        id: nextId++,
        ...req.body,
        createdAt: new Date(),
        updatedAt: new Date()
    };
    
    users.push(newUser);
    res.status(201).json(newUser);
};

export const updateUser = (
    req: Request<{ id: string }, User, UpdateUserDto>,
    res: Response<User | { message: string }>
) => {
    const id = parseInt(req.params.id);
    const index = users.findIndex(u => u.id === id);
    
    if (index === -1) {
        return res.status(404).json({ message: 'User not found' });
    }
    
    users[index] = {
        ...users[index],
        ...req.body,
        updatedAt: new Date()
    };
    
    res.json(users[index]);
};

export const deleteUser = (req: Request<{ id: string }>, res: Response<{ message: string }>) => {
    const id = parseInt(req.params.id);
    const index = users.findIndex(u => u.id === id);
    
    if (index === -1) {
        return res.status(404).json({ message: 'User not found' });
    }
    
    users.splice(index, 1);
    res.json({ message: 'User deleted successfully' });
};

13.7 用户路由

// src/routes/user.routes.ts
import { Router } from 'express';
import {
    getAllUsers,
    getUserById,
    createUser,
    updateUser,
    deleteUser
} from '../controllers/user.controller';
import { validate } from '../middleware/validation.middleware';

const router = Router();

const userValidationSchema = {
    name: { required: true, type: 'string' },
    email: { required: true, type: 'string', email: true },
    age: { required: true, type: 'number', min: 0 }
};

router.get('/', getAllUsers);
router.get('/:id', getUserById);
router.post('/', validate(userValidationSchema), createUser);
router.put('/:id', validate(userValidationSchema), updateUser);
router.delete('/:id', deleteUser);

export default router;

13.8 主应用文件

// src/app.ts
import express, { Application } from 'express';
import userRoutes from './routes/user.routes';
import { errorHandler, notFoundHandler } from './middleware/error.middleware';

const app: Application = express();

// 中间件
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// 路由
app.use('/api/users', userRoutes);

// 错误处理
app.use(notFoundHandler);
app.use(errorHandler);

export default app;

13.9 启动文件

// src/server.ts
import app from './app';

const PORT = process.env.PORT || 3000;

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

13.10 package.json脚本

{
  "scripts": {
    "dev": "nodemon --exec ts-node src/server.ts",
    "build": "tsc",
    "start": "node dist/server.js"
  }
}

13.11 运行项目

# 开发模式
npm run dev

# 生产构建
npm run build
npm start

十四、总结

TypeScript是JavaScript的超集,通过添加静态类型系统,让代码更加安全、可维护。通过本文的学习,你应该掌握了:

  1. TypeScript的基础概念和优势
  2. TypeScript的安装和配置
  3. 基础类型和类型注解
  4. 接口和类型别名
  5. 类和继承
  6. 泛型的使用
  7. 装饰器
  8. 高级类型和工具类型
  9. TypeScript与JavaScript的详细对比
  10. TypeScript最佳实践
  11. 完整的TypeScript + Express实战项目

TypeScript vs JavaScript主要变化

  1. 类型系统:从动态类型到静态类型,编译时就能发现错误
  2. 开发体验:更好的IDE支持,智能提示和重构
  3. 代码质量:类型注解让代码更易理解和维护
  4. 面向对象:完整的类、接口、抽象类支持
  5. 高级特性:泛型、装饰器、高级类型等
  6. 编译步骤:需要编译为JavaScript才能运行
  7. 学习曲线:比JavaScript更陡峭,但收益更大

学习建议

  • 从小项目开始,逐步迁移现有JavaScript项目
  • 充分利用IDE的类型提示和自动补全
  • 遵循严格的类型检查,避免使用any
  • 学习高级类型,提高代码复用性
  • 关注TypeScript的版本更新和新特性
  • 参考开源项目的TypeScript使用方式

TypeScript的学习是一个持续的过程,随着对类型系统的深入理解,你将能编写出更加健壮、可维护的代码。保持学习的热情,不断提升自己的技能,你一定能成为一名优秀的TypeScript开发者!


希望这篇TypeScript详解教程对你有所帮助!如果你有任何问题或建议,欢迎留言讨论。持续学习,不断进步,让我们一起在TypeScript的世界里探索更多可能性!

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐