速查 10 · TypeScript
按问题索引。Ctrl+F 页内搜索。 系统学习见 03 · TypeScript 进阶与 Dart 对照。
目录
- 基本类型怎么写
- 对象类型:interface vs type
- 联合 / 交叉 / 字面量
- 类型收窄
- 泛型
- 条件类型与 infer
- 映射类型与工具类型
- 函数:重载 / 可选 / this
- 异步与 Promise
- tsconfig 常用项
- 常见报错速查
基本类型怎么写
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、组件 Props | interface(可扩展、报错更友好) |
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 | 递归类型太深,给条件类型加"终止分支" |