TypeScript总结

简介

TypeScript 是 JavaScript 的超集(Superset),由微软开发并开源。它在 JavaScript 的基础上添加了静态类型系统和基于类的面向对象编程特性。

只是在编译阶段帮你找出类型错误,编译后输出的仍然是纯 JS。

优势:

特性 说明
静态类型检查 在编译时发现类型错误,减少运行时 Bug
更好的IDE支持 智能提示、代码补全、重构支持
增强的可维护性 大型项目更易理解和维护
现代JS特性 支持 ES6+ 语法,并编译为兼容的 JavaScript
丰富的生态系统 几乎所有流行库都有类型定义, Vue / React / Node.js 主流框架全面支持

文件扩展名

扩展名 用途
.ts 标准的 TypeScript 文件(最常用)
.tsx 支持 JSX 语法的 TypeScript 文件(用于 React 项目)
.d.ts 类型声明文件(只包含类型定义,无具体实现)
.mts / .cts 分别用于 ESM 和 CommonJS 模块的 TypeScript 文件(TS 4.7+)

经过 TypeScript 编译器(tsc)编译后,会生成对应的 JavaScript 文件

语法

基础类型

// 原始类型
let isDone: boolean = false;
let count: number = 42;
let userName: string = "Alice";

// 数组
let numbers: number[] = [1, 2, 3];
let names: Array<string> = ["Tom", "Jerry"];  // 泛型写法

// 元组 - 固定长度和类型
let person: [string, number] = ["Alice", 25];

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

// Any - 任意类型(慎用)any 会关闭类型检查,等于写回 JS。如果确实不知道类型,用 unknown,它要求你在使用前做类型检查。
let notSure: any = 4;
notSure = "maybe a string";

// Unknown - 类型安全的 any
let unknownValue: unknown = 4;
// 使用前需要类型检查或断言

// Void - 无返回值
function warnUser(): void {
    console.log("This is a warning");
}

// Never - 永不返回(如抛出异常或无限循环)
function throwError(message: string): never {
    throw new Error(message);
}

对象类型

// 内联对象类型
let user: {
  name: string
  age: number
  email?: string       // ? 表示可选属性
  readonly id: number    // readonly 表示只读
} = {
  name: '张三',
  age: 25,
  id: 1001
}

user.email = 'a@b.com'  // ✅ 可选属性可以后赋值
user.id = 2002            // ❌ 只读属性不能修改

接口(Interface)

定义对象的结构,是 TypeScript 最核心的特性之一:

interface User {
  id: number
  name: string
  age: number
  email?: string              // 可选
  readonly createdAt: Date    // 只读
}

// 使用
const user: User = {
  id: 1,
  name: '张三',
  age: 25,
  createdAt: new Date()
}

// 缺少必填属性会报错
const bad: User = { id: 2, name: '李四' } // ❌ 缺少 age 和 createdAt

interface 继承

interface Animal {
  name: string
  speak(): void
}

interface Dog extends Animal {
  breed: string
  fetch(item: string): void
}

const myDog: Dog = {
  name: '旺财',
  breed: '柴犬',
  speak() { console.log('汪汪') },
  fetch(item) { console.log(`捡回 ${item}`) }
}

type — 类型别名

// type 能定义任何类型,不只是对象
type ID = string | number
type Status = 'pending' | 'done' | 'failed'
type Callback = (data: string) => void

// 对象类型(和 interface 类似)
type Point = {
  x: number
  y: number
}

// 交叉类型实现"继承"效果
type Point3D = Point & { z: number }

// 从已有类型映射出新类型
type ReadOnlyUser = Readonly<User>
type PartialUser = Partial<User>  // 所有属性变可选

interface vs type 怎么选

特性 interface type
扩展方式 extends 继承 & 交叉
重复声明 自动合并(声明合并) 不允许重复
能定义的范围 仅对象形状 任何类型(联合、元组、函数等)
适用场景 定义类的形状、库的 API 联合类型、工具类型、复杂类型运算

简单规则:定义对象结构用 interface,其他一切用 type。

联合类型与字面量类型

// 联合类型 — 多种类型选其一
let id: string | number = 'abc'
id = 123  // ✅

// 字面量类型 — 限定为固定值
let direction: 'up' | 'down' | 'left' | 'right' = 'up'
direction = 'diagonal'  // ❌

// 组合使用
let status: 'loading' | 'success' | 'error' = 'loading'

类(Class)

class Person {
  // 访问修饰符:public(默认)| private | protected
  public name: string
  private _age: number       // 仅类内部可访问
  protected id: number       // 类内部 + 子类可访问

  // 构造函数参数可以直接加修饰符(简写)
  constructor(name: string, private _age: number, protected id: number) {
    this.name = name
  }

  // getter / setter
  get age(): number { return this._age }
  set age(val: number) {
    if (val >= 0) this._age = val
  }

  greet(): string {
    return `我是 ${this.name},${this._age} 岁`
  }
}

const p = new Person('张三', 25, 1)
p.name   // ✅ public
p.age    // ✅ 通过 getter
p._age   // ❌ private,外部不可访问
p.id     // ❌ protected,外部不可访问

继承与抽象类

// 抽象类 — 不能直接实例化,必须被继承
abstract class Shape {
  abstract getArea(): number  // 子类必须实现

  describe(): string {
    return `面积为 ${this.getArea().toFixed(2)}`
  }
}

class Circle extends Shape {
  constructor(public radius: number) { super() }

  getArea(): number {
    return Math.PI * this.radius ** 2
  }
}

class Rectangle extends Shape {
  constructor(public w: number, public h: number) { super() }

  getArea(): number {
    return this.w * this.h
  }
}

const shapes: Shape[] = [new Circle(5), new Rectangle(3, 4)]
shapes.forEach(s => console.log(s.describe()))

枚举

// 数字枚举(默认从 0 开始)
enum Direction {
  Up,      // 0
  Down,    // 1
  Left,    // 2
  Right    // 3
}
const d: Direction = Direction.Up

// 字符串枚举(推荐,可读性更好)
enum Status {
  Pending = 'pending',
  Success = 'success',
  Failed  = 'failed'
}

function handle(status: Status) {
  if (status === Status.Success) { /* ... */ }
}

// 实际开发中,更推荐用联合类型替代枚举(更轻量)
type Status2 = 'pending' | 'success' | 'failed'

枚举 vs 联合类型:枚举会生成额外的 JS 代码,而联合类型是零成本的类型级约束。如果没有反向映射的需求,优先用联合类型。

基本函数类型

// 普通函数
function greet(name: string): string {
  return `你好,${name}`
}

// 箭头函数
const add = (a: number, b: number): number => a + b

// 无返回值
function log(msg: string): void {
  console.log(msg)
}

// 永远不会正常返回
function fail(msg: string): never {
  throw new Error(msg)
}

 

可选参数与默认值

// 可选参数用 ? ,必须放在最后
function createUser(name: string, age?: number): void {
  console.log(name, age)  // age 可能是 undefined
}

// 默认值参数(不需要 ?)
function request(url: string, method: string = 'GET'): void {
  // method 不传时默认 'GET'
}

// 剩余参数
function sum(...nums: number[]): number {
  return nums.reduce((a, b) => a + b, 0)
}

函数类型表达式

// 用 type 定义函数签名
type Fn = (x: number, y: number) => number

const multiply: Fn = (a, b) => a * b

// 回调函数类型
function fetchData(url: string, onSuccess: (data: any) => void): void {
  // ...
}

fetchData('/api', (data) => {
  console.log(data)  // data 自动推断为 any
})

函数重载

function parse(input: string): number      // 重载签名 1
function parse(input: number): string      // 重载签名 2
function parse(input: string | number): string | number {  // 实现签名
  if (typeof input === 'string') return Number(input)
  return String(input)
}

parse('123')   // 返回类型推断为 number
parse(456)    // 返回类型推断为 string

类型收窄与守卫

为什么需要类型收窄
联合类型的变量不能直接调用某个类型特有的方法,必须先"收窄"到具体类型:

function process(val: string | number) {
  console.log(val.toUpperCase())  // ❌ number 没有 toUpperCase
}

收窄方式

// 1. typeof
function process(val: string | number) {
  if (typeof val === 'string') {
    console.log(val.toUpperCase())  // ✅ 此处 val 收窄为 string
  } else {
    console.log(val.toFixed(2))       // ✅ 此处 val 收窄为 number
  }
}

// 2. 真值检查(排除 null / undefined / "" / 0 / false)
function len(s: string | null) {
  if (s) {
    console.log(s.length)  // ✅ 此处 s 收窄为 string
  }
}

// 3. in 操作符
type Fish = { swim: () => void }
type Bird = { fly: () => void }
function move(pet: Fish | Bird) {
  if ('swim' in pet) {
    pet.swim()  // ✅ 收窄为 Fish
  } else {
    pet.fly()   // ✅ 收窄为 Bird
  }
}

// 4. instanceof
function format(val: Date | string) {
  if (val instanceof Date) {
    console.log(val.toISOString())  // ✅ 收窄为 Date
  }
}

// 5. 自定义类型守卫(is 关键字)
function isFish(pet: Fish | Bird): pet is Fish {
  return ('swim' in pet)
}

const pet: Fish | Bird = { swim: () void 0 }
if (isFish(pet)) {
  pet.swim()  // ✅ 自定义守卫让 TS 自动收窄
}

泛型(Generics)

泛型就是类型的变量——你先不确定具体类型,用占位符代替,等到使用时再确定。就像函数的参数一样,只不过参数是类型。

编写可复用的、类型安全的代码:

// 不用泛型 — 要为每种类型写一遍
function identityStr(x: string): string { return x }
function identityNum(x: number): number { return x }

// 用泛型 — 一个函数搞定所有类型
function identity<T>(x: T): T {
  return x
}

identity('hello')   // T 推断为 string,返回 string
identity(42)        // T 推断为 number,返回 number
identity<boolean>(true)  // 手动指定 T 为 boolean
// 泛型接口
interface ApiResponse<T> {
  code: number
  message: string
  data: T
}

// 使用时传入具体类型
type UserResponse = ApiResponse<{ id: number; name: string }>
type ListResponse = ApiResponse<string[]>

// 实际数据
const res: UserResponse = {
  code: 200,
  message: 'ok',
  data: { id: 1, name: '张三' }
}
res.data.name  // ✅ 自动补全
res.data.age   // ❌ 报错:{ id: number; name: string } 上不存在 age

泛型约束
有时候泛型不能是任意类型,需要加上约束:

// 约束 T 必须有 length 属性
interface HasLength { length: number }

function logLength<T extends HasLength>(val: T): void {
  console.log(val.length)
}

logLength('hello')    // ✅ string 有 length
logLength([1, 2])      // ✅ 数组有 length
logLength(123)        // ❌ number 没有 length

// 约束 T 必须是某个类的子类型
function getById<T extends { id: number }>(items: T[], id: number): T | undefined {
  return items.find(item => item.id === id)
}

常用内置工具类型

工具类型 作用 示例
Partial<T> 所有属性变可选 Partial<User>
Required<T> 所有属性变必填 Required<User>
Readonly<T> 所有属性变只读 Readonly<User>
Pick<T, K> 只保留部分属性 Pick<User, 'id' | 'name'>
Omit<T, K> 排除部分属性 Omit<User, 'password'>
Record<K, V> 构造键值对类型 Record<string, number>
Array<T> 数组类型 Array<string>
interface User { id: number; name: string; email: string; age: number }

type UserUpdate = Partial<User>
// { id?: number; name?: string; email?: string; age?: number }

type UserPreview = Pick<User, 'id' | 'name'>
// { id: number; name: string }

type UserSafe = Omit<User, 'email'>
// { id: number; name: string; age: number }

type RoleMap = Record<string, string[]>
// { [key: string]: string[] }
const roles: RoleMap = {
  admin: ['read', 'write', 'delete'],
  user:  ['read']
}

 

 

 

高级类型

// 联合类型(Union Types)
function padLeft(value: string, padding: string | number) {
    if (typeof padding === "number") {
        return Array(padding + 1).join(" ") + value;
    }
    return padding + value;
}

// 类型断言
let someValue: unknown = "this is a string";
let strLength: number = (someValue as string).length;
// 或 let strLength: number = (<string>someValue).length;

// 类型守卫
function isString(test: any): test is string {
    return typeof test === "string";
}

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

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

// 实用工具类型
interface Todo {
    title: string;
    description: string;
}

type TodoPreview = Pick<Todo, "title">;           // 选取属性
type TodoPartial = Partial<Todo>;                  // 所有属性可选
type TodoReadonly = Readonly<Todo>;                // 所有属性只读
type TodoRequired = Required<Todo>;                // 所有属性必选

模块与命名空间

// 导出
export interface StringValidator {
    isValid(s: string): boolean;
}

export const numberRegexp = /^[0-9]+$/;

export default class ZipCodeValidator implements StringValidator {
    isValid(s: string): boolean {
        return s.length === 5 && numberRegexp.test(s);
    }
}

// 导入
import { StringValidator } from "./StringValidator";
import ZipCodeValidator from "./ZipCodeValidator";
import * as validator from "./ZipCodeValidator";  // 命名空间导入

装饰器(Decorators)

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

@sealed
class Greeter {
    greeting: string;
    constructor(message: string) {
        this.greeting = message;
    }
}

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

 

posted @ 2026-04-14 11:35  星光闪闪  阅读(20)  评论(0)    收藏  举报