TypeScript 概览

自动关联目录:TypeScript 概览

心智模型:类型是一个集合

把类型理解成"值的集合",很多规则就自然了:

写法集合含义
string所有字符串的集合
'a' | 'b'只含两个元素的集合
A & B交集(同时满足)
A | B并集(满足其一)
unknown全集
never空集

赋值是否合法 = 源集合是否是目标集合的子集。这就是为什么 string 不能赋给 'a',反之可以。

基础类型

类型说明
string number boolean原始类型
bigint symbol需要对应 target 支持
null undefined严格模式下独立
void函数无返回值
never永不返回(抛错、死循环)
unknown未知,使用前必须收窄
any关闭检查
object / {}注意 {} 也接受基本类型,别用来表示"任意对象"

unknown 与 any 的区别是最常被问到的:两者都能接受任何值,但 unknown 不允许直接使用,必须先收窄。所以新代码里凡是想写 any,先考虑 unknown。

收窄(Narrowing)

类型守卫让编译器把联合类型收敛到具体分支:

function len(x: string | string[]) {
    if (typeof x === "string") return x.length;  // 此处 x: string
    return x.length;                              // 此处 x: string[]
}
守卫适用
typeof原始类型
instanceof类实例
in判断属性/方法存在
字面量比较判别联合(discriminated union)
自定义谓词 x is T复杂判断
Array.isArray数组

判别联合是最值得掌握的模式:

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

function handle(r: Result) {
    switch (r.kind) {
        case "ok":  return r.data;   // r 已收窄
        case "err": return r.msg;
    }
}

接口与类型别名

interfacetype
对象形状可以可以
联合/交叉/元组/条件类型不行可以
声明合并支持(可多次声明累加)不支持
扩展extends&

实践建议:描述对象形状用 interface,其他一切用 type。这个约定让代码风格统一,也避开了 interface 不能表达联合的限制。

泛型

function first<T>(xs: T[]): T | undefined { return xs[0]; }

泛型是"类型层面的函数":输入类型,输出类型。

机制用途
<T>类型参数
extends约束(T extends { id: string })
keyof T取键的联合
T[K]索引访问类型
默认参数 <T = string>减少重复书写

实用内置类型

类型效果
Partial<T>全部可选
Required<T>全部必填
Pick<T, K> / Omit<T, K>挑/去若干键
Record<K, V>键值映射
Readonly<T>只读
ReturnType<F> / Parameters<F>从函数类型反推
Awaited<T>展开 Promise
NonNullable<T>去 null/undefined

与 JavaScript 的关系

  • TS 只做编译期类型检查,运行时类型信息被擦除
  • enum 与 namespace 是少数会生成运行时代码的 TS 特性
  • private 只是编译期约束,运行时仍是普通属性(要真私有用 #field)
  • interface 编译后完全消失,不能用作运行时判断

常见错误

错误原因
Object is possibly 'undefined'索引/可选属性没收窄
Type 'X' is not assignable to 'Y'集合不是子集,通常字段少了
This expression is not callable联合类型里各方签名不一致
过度使用 as用守卫收窄更安全
strict 关着时"能编译但运行时崩"类型没真正生效