Skip to content

速查 10 · TypeScript ​

按问题索引。Ctrl+F 页内搜索。 系统学习见 03 · TypeScript 进阶与 Dart 对照。

目录 ​


基本类型怎么写 ​

ts
const name: string = 'sunqy'
const age: number = 18            // 没有 int/float,都是 number
const ok: boolean = true
const tags: string[] = ['a', 'b'] // 数组
const tuple: [string, number] = ['x', 1] // 元组(固定长度+类型)
const anything: unknown = fetch()  // 未知类型,用前必须收窄
const neverThing: never = (() => { throw new Error('no') })()
let maybe: string | null = null   // 联合 + 空值

// null/undefined 的区别:undefined 是"没赋值",null 是"显式空"
// 严格模式下(strict: true),null 和 undefined 不能互相替换

对象类型:interface vs type ​

场景用哪个
定义对象结构、可被继承/合并interface
联合类型、交叉类型、函数类型别名type
后端 DTO、组件 Propsinterface(可扩展、报错更友好)
ts
interface User {
  id: number
  name: string
  email?: string        // 可选
  readonly createdAt: string // 只读,赋值后不可改
}

type Result = { ok: true; data: User } | { ok: false; error: string }

// interface 同名自动合并(type 不行)
interface User { age?: number }

// 索引签名:动态键
interface Dict {
  [key: string]: number | string
}

联合 / 交叉 / 字面量 ​

ts
type ID = number | string        // 联合:满足其一
type Full = A & B                // 交叉:两个都要("和")
type Status = 'idle' | 'loading' | 'success' | 'error' // 字面量联合 = 受限枚举

// 替代 enum 的推荐写法:常量 + 字面量联合(enum 有运行时对象,as const 没有)
const HTTP_METHOD = ['GET', 'POST', 'PUT'] as const
type HttpMethod = (typeof HTTP_METHOD)[number] // "GET" | "POST" | "PUT"

类型收窄 ​

ts
function f(x: string | number | null) {
  if (typeof x === 'string') return x.length   // string
  if (typeof x === 'number') return x.toFixed(2)
  return x // 这里 x 是 null(严格模式已排除 string/number)
}

// 判别联合:靠一个字段区分(最常用,可读性好)
interface Dog { kind: 'dog'; bark(): void }
interface Cat { kind: 'cat'; meow(): void }
type Pet = Dog | Cat
function speak(pet: Pet) {
  if (pet.kind === 'dog') pet.bark()  // TS 自动收窄到 Dog
}

// in / instanceof / 数组判断
if ('bark' in pet) { /* Dog */ }
if (err instanceof Error) { /* Error */ }
if (Array.isArray(x)) { /* T[] */ }

泛型 ​

ts
function identity<T>(x: T): T { return x }
identity<string>('a') // 显式
identity('a')          // 自动推断

// 约束:T 必须可比较
function max<T extends { length: number }>(a: T, b: T): T {
  return a.length >= b.length ? a : b
}

// 泛型接口:常见于仓储层
interface Repository<T> {
  find(id: number): Promise<T>
  save(item: T): Promise<void>
}

// 默认类型参数
type Box<T = string> = { value: T }

条件类型与 infer ​

ts
type IsString<T> = T extends string ? true : false
type A = IsString<'x'>  // true
type B = IsString<1>    // false

// infer:从类型里"掏出"一部分
type ElementOf<T> = T extends (infer E)[] ? E : never
type C = ElementOf<string[]> // string

// 常用实例:取 Promise 的返回值
type Unwrap<T> = T extends Promise<infer U> ? U : T
type D = Unwrap<Promise<number>> // number

映射类型与工具类型 ​

ts
// 映射类型:遍历键
type ReadonlyAll<T> = { readonly [K in keyof T]: T[K] }

// 内置工具类型(最常用,别自己造)
Partial<T>      // 全部可选
Required<T>     // 全部必填
Pick<T, 'id' | 'name'>   // 挑出指定键
Omit<T, 'id'>            // 排除指定键
Record<K, V>    // 构建对象:Record<'a'|'b', number>
Exclude<A, B>   // 从 A 去掉 B 中的类型
Extract<A, B>   // 取 A、B 交集
NonNullable<T>  // 去掉 null/undefined
ReturnType<F>   // 函数返回类型
Parameters<F>   // 函数参数元组
Awaited<Promise<T>> // Promise 的返回值(自动展开多层)

// 例子:后端返回的 DTO 转表单模型
type CreateUserInput = Omit<User, 'id' | 'createdAt'>

函数:重载 / 可选 / this ​

ts
// 可选参数 / 默认值
function greet(name: string, prefix = 'Hi'): string {
  return `${prefix}, ${name}`
}

// 函数类型标注
type Callback = (err: Error | null, data?: User) => void

// 函数重载:不同入参返回不同类型
function parse(input: string): number
function parse(input: string[]): number[]
function parse(input: string | string[]): number | number[] {
  if (Array.isArray(input)) return input.map(Number)
  return Number(input)
}

// 显式 this(strict 下 this 不再默认 any)
function log(this: { name: string }) {
  console.log(this.name)
}

异步与 Promise ​

ts
async function fetchUser(id: number): Promise<User> {
  const res = await fetch(`/api/users/${id}`)
  if (!res.ok) throw new Error(`HTTP ${res.status}`)
  return res.json()
}

// 并发:Promise.all 有"一错全错"问题
const [a, b] = await Promise.all([fetchUser(1), fetchUser(2)])

// 容错写法:每个失败都独立记录,不拖垮整体
const results = await Promise.allSettled([p1, p2])
// results: Array<{status:'fulfilled',value} | {status:'rejected',reason}>

// 超时兜底
const withTimeout = <T>(p: Promise<T>, ms: number) =>
  Promise.race([p, new Promise<never>((_, rej) =>
    setTimeout(() => rej(new Error('timeout')), ms))])

tsconfig 常用项 ​

jsonc
{
  "compilerOptions": {
    "strict": true,                 // 必开:null/undefined/隐式 any 全部检查
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",  // Vite/现代打包器用
    "skipLibCheck": true,           // 跳过 .d.ts 类型检查,加速
    "esModuleInterop": true,        // import express from 'express' 这种默认导出
    "noUncheckedIndexedAccess": true, // arr[i] 可能是 undefined(更安全,但更严格)
    "paths": { "@/*": ["./src/*"] } // 路径别名,配合打包器 resolve.alias
  }
}

常见报错速查 ​

报错含义 / 解法
Object is possibly 'undefined'严格模式访问可能为 undefined 的值,先收窄或 ?. / ??
Cannot find module 'x'缺类型声明,装 @types/x;或加 declaration.d.ts
Type 'x' is not assignable to type 'y'类型不匹配,检查联合/可选;必要时用 as(慎用)
'this' implicitly has type 'any'回调里用 this,改用箭头函数或显式标注
Element implicitly has an 'any' type数组索引需要 noUncheckedIndexedAccess 或先判空
Property 'x' does not exist on type 'y'类型没这个字段,检查接口/DTO 定义
Excessive stack depth comparing types递归类型太深,给条件类型加"终止分支"