TypeScript 基础知识参考字典

这本字典怎么用

按用途分七组:类型标注、接口与别名、泛型、工具类型、类型收窄、模块与配置、报错速查。每条四件事:签名、一句话语义(写”什么时候用、和谁的区别”)、最小示例、常见坑。字典是查的不是读的——先搜文末速查表定位,再跳回条目。

概念背景见TypeScript 语法要点;条目里的运行环境为 Node.js + tsc,报错行为以 strict 模式为准。

一、类型标注

组内共性:标注是契约不是注释,多数位置靠推断;标注的主战场是函数参数与导出 API。

let x: T = v(变量标注)

显式声明变量类型,推断会出错或想放宽时才用。

let ids: string[] = [];
let pair: [string, number] = ["a", 1];  // 元组:长度与各位类型都固定

坑:元组是定长的,push 之后长度信息与类型脱节,运行时可能比类型认的更长。

function f(a: T): R(函数签名标注)

参数没有推断来源必须标;导出函数的返回值建议标,把承诺写死在定义处。

export function parseIds(raw: string): number[] {
  return raw.split(",").map(Number);
}

坑:可选参数 flag?: boolean 实际是 boolean | undefined,与默认值 flag = false 的行为不同——后者不必传且不产生 undefined。

字面量类型与 as const

把值本身当类型,适合枚举式取值;as const 让对象与数组的一切推断落到字面量。

let status: "open" | "closed" = "open";
const dirs = ["up", "down"] as const;  // readonly ["up","down"]

坑:let x = "hello" 推断为 string(可变变量放宽),只有 const 或 as const 才保住字面量。

readonly 与 ?

readonly 编译期禁改(运行时无效);? 标记可能缺失。

interface Point { readonly x: number; y?: number }
const p: Point = { x: 1 };
// p.x = 2  // 报错

坑:readonly 不递归——readonly T[] 禁止改数组,元素内部照改不误。

二、接口与别名

组内共性:都能描述对象形状;type 能做类型运算,interface 能被重复声明合并与 extends。

interface

描述对象/函数形状,可被 extends 扩展、可同名合并(declaration merging)。

interface Todo { id: string; done: boolean }
interface Todo { text: string }  // 与上合并,Todo 现在有三个字段

坑:同名静默合并是库扩展机制,业务代码里两个文件同名 interface 会把字段悄悄混进来,排查困难。

type

给任意类型起名:联合、元组、映射、条件类型的唯一载体。

type ID = string | number;
type Handler = (e: string) => void;

坑:type 无合并特性,重名直接报错——这反而是优点。

extends 与交叉 &

interface 用 extends 继承,type 用 & 组合;都表达”且”。

interface Base { id: string }
interface Task extends Base { done: boolean }
type Task2 = Base & { done: boolean };

坑:交叉时同名字段类型冲突会得到 never,见语法要点篇的例子。

索引签名 [k: string]: T

描述”任意键都映射到 T”,动态键容器用。

interface Counts { [key: string]: number }
const c: Counts = { ok: 1, fail: 0 };

坑:索引签名放行任意键,拼错键名不报错——确定键集合时用 Record 更严。

三、泛型

组内共性:把类型做成参数,保住输入输出之间的类型关联;先有第二形态再抽象。

泛型函数

让调用方决定类型,函数体保住关联。

function firstOr<T>(list: T[], fallback: T): T {
  return list.length ? list[0] : fallback;
}

坑:函数体用不到类型关联时不要写泛型——那是装饰,不是抽象。

T extends U(约束)

限制类型参数的范围,换取在函数体内使用 U 成员的资格。

function len<T extends { length: number }>(x: T): number {
  return x.length;  // 无约束这里就报错
}

坑:约束过宽等于没约束,过窄调用方处处断言;从”函数体真正用了什么”倒推。

默认类型参数 T = D

调用方不传时的兜底类型。

function fetchJson<T = unknown>(url: string): Promise<T>;
// 不显式传 T 时拿到 unknown,逼调用方校验

坑:默认 any 是坏默认——校验压力被转移给每一个调用点。

四、工具类型与类型运算

组内共性:类型层面的函数,输入类型输出类型;组合使用时从内往外读。

keyof T

取对象类型的所有键组成联合。

interface Todo { id: string; done: boolean }
type TodoKey = keyof Todo;  // "id" | "done"

坑:keyof 拿的是类型声明的键,运行时对象多出来的键不在其中。

typeof x(类型查询)

从已有值反取类型,配置对象与常量表常用。

const defaults = { host: "127.0.0.1", port: 8080 };
type Defaults = typeof defaults;  // { host: string; port: number }

坑:与值层面的 typeof 运算符同名不同物——一个在类型位置,一个在表达式位置。

Partial / Required

全部属性变可选 / 变必填;更新接口入参的标准姿势。

function update(id: string, patch: Partial<Todo>) { /* ... */ }
update("t1", { done: true });  // 只传要改的

坑:Partial 连 id 也变可选,更新入参想排除某些字段用 Pick 组合。

Pick / Omit

挑字段 / 删字段,产出视图类型。

type TodoBrief = Pick<Todo, "id">;
type TodoDraft = Omit<Todo, "id">;  // 创建入参:id 由服务端生成

坑:K 写了 T 里不存在的键不总是报错(联合宽化场景),键名靠字面量保真。

Record

键集合 K 到 V 的映射,比索引签名严格。

type Env = "dev" | "prod";
const urls: Record<Env, string> = { dev: ":8080", prod: ":443" };
// 少写一个环境的键,编译期就报错

坑:K 是 string 时退化为索引签名,失去键检查。

ReturnType / Awaited

取函数返回类型 / 解开 Promise 拿到最终值类型。

declare function loadTodo(): Promise<Todo>;
type One = Awaited<ReturnType<typeof loadTodo>>;  // Todo

坑:异步函数必须 Awaited 包 ReturnType,否则拿到的是 Promise 包装。

五、类型收窄与断言

组内共性:联合类型靠收窄变成可用类型;断言是收窄的替代品,每次使用都该有理由。

typeof 收窄

原始类型分支的默认触发器。

function size(x: string | string[]): number {
  return typeof x === "string" ? x.length : x.join("").length;
}

坑:typeof null === “object”,判空用 x === null。

instanceof / in

类实例判别 / 键存在性判别。

if (err instanceof TypeError) { /* ... */ }
if ("code" in err) { console.log(err.code); }

坑:跨 realm(iframe、vm 模块)实例的原型链不同,instanceof 会失手。

判别联合 + switch

互斥状态的标准建模:字面量判别字段 + 穷尽 switch。

type State =
  | { kind: "idle" }
  | { kind: "ok"; data: string }
  | { kind: "err"; msg: string };

function view(s: State) {
  switch (s.kind) {
    case "idle": return "待机";
    case "ok":   return s.data;   // 收窄成功
    default:     return s.msg;
  }
}

坑:判别字段必须是字面量类型;写成 string 就失去判别力。

类型谓词 x is T

自定义校验函数的返回类型,让 if 之后自动收窄。

function isTodo(x: unknown): x is Todo {
  return typeof x === "object" && x !== null && "id" in x;
}
const raw: unknown = JSON.parse(text);
if (isTodo(raw)) view({ kind: "ok", data: raw.id });

坑:谓词只做类型层面的信任,函数体写错(恒真)编译器不查——校验逻辑要自己负责。

非空断言 !

告诉编译器”这里不会是 null/undefined”,绕过检查。

const el = document.getElementById("app")!;

坑:运行时真没有就是 TypeError,把检查义务转移给了未来的自己。

as 断言 / satisfies

as 强制改类型(骗编译器);satisfies 验形状且保推断(TS 4.9+)。用 as 覆盖校验逻辑是字典里最典型的反模式:编译器闭嘴不等于类型对了,脏数据从此带毒运行。

const cfg = { retries: 3 } satisfies Record<string, number>;
const n = "42" as unknown as number;  // 双重断言:几乎必错

坑:as 不做任何转换,只是闭嘴;能 satisfies 或校验解决的不要 as。

六、模块与配置(tsconfig 关键项)

组内共性:tsconfig 决定编译器严格程度与模块解析方式;从 strict 起步,按需加码。

strict: true

严格系开关的总闸(strictNullChecks、noImplicitAny 等一并生效)。新项目无脑开,存量项目开它是 ROI 最高的一次性投入。

{ "compilerOptions": { "strict": true } }

坑:不开 strictNullChecks 时 undefined 不在类型里,本文一半的收窄条目都失去意义。

noUncheckedIndexedAccess

索引访问返回 T | undefined,承认”数组可能越界、键可能不存在”。

const xs = [1, 2];
const a = xs[0];  // number | undefined,用前必须收窄

坑:开了它之后旧代码大量报错,建议新项目直接开、老项目随迭代推进。

module / moduleResolution

module 定输出模块格式(esnext / nodenext / node20 等),moduleResolution 定找模块的方式,两者要配套(nodenext 配 nodenext,bundler 配打包器场景)。

{ "module": "nodenext", "moduleResolution": "nodenext" }

坑:Node 直接跑(不经打包)却配 bundler,运行时扩展名解析行为对不上。

verbatimModuleSyntax 与 import type

强制类型导入显式化:import type 的内容编译后被整体擦除,不产生运行时导入。

import type { Todo } from "./todo.js";  // 纯类型,擦除
import { loadTodo } from "./todo.js";    // 有运行时效果

坑:编译产物是 JS,相对导入要写 .js 扩展名(tsc 按 JS 输出解析),漏写运行时找不到模块。

isolatedModules

假设每个文件会被单文件转译器(esbuild、swc)单独处理,禁止跨文件的类型再导出等隐式依赖。多数构建链与转译运行工具都要求它,建议常开。

坑:export { SomeType } from ... 这种不标 type 的重导出直接报错——这正是它要拦的。

paths(路径别名)

编译期把 @/x 映射到 src/x,消除 ../../。

{ "baseUrl": ".", "paths": { "@/*": ["src/*"] } }

坑:paths 只影响 tsc 的类型检查与认 tsconfig 的打包器,Node 直接运行编译产物不认,需要运行时侧对应配置。

七、常见报错速查

按”看到这条先检查什么”组织,全部以 strict 模式为准:

报错码 典型信息 先检查什么
TS2322 / TS2345 Type ‘x’ is not assignable to type ‘y’ 两边形状差在哪:缺字段、多了字段(多余属性检查只在字面量上触发)、字面量被放宽
TS2339 Property ‘p’ does not exist on type ‘T’ 用之前收窄了吗:联合未收窄时只能碰公共成员
TS2532 / TS18048 possibly ‘undefined’ 加空值分支、默认值 ?? 或 if 收窄;非空断言 ! 是最后手段
TS7006 Parameter implicitly has an ‘any’ type 没开 strict 或漏标参数;补标注而不是关检查
TS2352 Conversion of type may be a mistake as 两边类型无重叠,多半该用类型谓词校验而不是断言
TS2304 / TS2307 Cannot find name / module 相对导入扩展名(.js)、paths 是否运行时生效、package.json 的 type 字段
TS2769 No overload matches this call 看最后一个重载的报错细节,多半是参数顺序或形状差一点
TS2564 Property has no initializer strict 下类字段必须初始化或标 !: 断言赋值

全量速查表

条目 一句话用途 坑
let x: T 显式定类型 推断已有就别标
函数标注 参数必标、导出返回值建议标 ? 与默认值不等价
字面量/as const 值当类型用 let 推断会放宽
readonly / ? 禁改 / 可缺失 readonly 不递归
interface 可扩展的形状 同名静默合并
type 类型运算载体 重名报错(是优点)
extends / & 继承与组合 冲突字段交叉成 never
索引签名 任意键容器 拼错键不报错
泛型 保类型关联 没关联别用泛型
extends 约束 给类型参数立法 宽窄要贴函数体
默认 T = D 兜底类型 默认 any 是坏默认
keyof 取键联合 不含运行时多余的键
typeof(类型) 从值取类型 与值层 typeof 同名
Partial / Required 全可选 / 全必填 连 id 也可选
Pick / Omit 挑 / 删字段 键名要字面量保真
Record 键集到值的映射 K 写 string 就退化
ReturnType / Awaited 取返回 / 解 Promise 异步记得套 Awaited
typeof 收窄 原始类型分支 typeof null 是 object
instanceof / in 实例 / 键判别 跨 realm 失手
判别联合 互斥状态建模 判别字段须字面量
x is T 自定义校验收窄 函数体写错没人查
非空 ! 绕空值检查 运行时真空就炸
as / satisfies 改类型 / 验形状 as 只是闭嘴不转换
strict 严格总闸 不开则收窄全失效
noUncheckedIndexedAccess 索引访问认账越界 旧代码报错量大
module 组合 模块格式与解析 运行方式要配套
verbatimModuleSyntax 类型导入显式化 导入要写 .js 后缀
isolatedModules 单文件转译安全 拦隐式类型重导出
paths 路径别名 运行时不认
报错速查 见第七节表 以 strict 为准

延伸阅读

版本说明:截至写作(2025-02-22),npm latest 为 TypeScript 5.7.x(2024-11 发布);本文条目语法跨 5.x 适用(satisfies 需 4.9+,verbatimModuleSyntax 需 5.0+)。tsconfig 具体项行为以官方文档为准。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇