TS 术语解释
TypeScript 文档和社区讨论中频繁出现一些专业术语,理解这些术语有助于读懂错误信息、官方文档以及他人代码。
Assignability(可赋值性)
描述一个类型的值是否可以赋给另一个类型的变量。TS 的类型检查本质上就是在做 assignability 判断。
let a: string = 'hello'
let b: string | number = a // ✅ string 可赋值给 string | number
let c: number = a // ❌ string 不可赋值给 numberNarrowing(类型收敛)
通过条件判断让 TS 将一个宽泛的类型"收敛"到更具体的类型。常见的收敛方式有 typeof、instanceof、in、字面量相等判断等。
function print(val: string | number) {
if (typeof val === 'string') {
// 此处 val 被收敛为 string
console.log(val.toUpperCase())
}
}Widening(类型扩展)
与 Narrowing 相反,TS 在某些场景下会自动将字面量类型"扩宽"为对应的基础类型。
let a = 'hello' // 推断为 string,而非字面量类型 'hello'
const b = 'hello' // 推断为字面量类型 'hello',const 阻止了扩宽Type Inference(类型推断)
TS 自动根据值或上下文推导出类型,无需手动标注。
const name = 'xiaoming' // 推断为 string
const nums = [1, 2, 3] // 推断为 number[]
const add = (a: number, b: number) => a + b // 返回值推断为 numberStructural Typing(结构类型 / 鸭子类型)
TS 不通过类名判断类型兼容性,而是通过**结构(属性的形状)**来判断。只要结构匹配,类型就兼容。
interface Point {
x: number
y: number
}
function logPoint(p: Point) {
console.log(p.x, p.y)
}
// 没有显式声明 implements Point,但结构匹配,可以直接传入
const pos = { x: 10, y: 20, z: 30 }
logPoint(pos) // ✅Nominal Typing(名义类型)
与 Structural Typing 相对,Java/C# 等语言采用名义类型:即使结构完全相同,不同名称的类型也不兼容。TS 默认不是名义类型,但可以用 brand 技术模拟。
Type Alias vs Interface(类型别名 vs 接口)
两者都可以描述对象形状,区别在于:
| 对比点 | type alias | interface |
|---|---|---|
| 扩展方式 | & 交叉类型 | extends 继承 |
| 声明合并 | ❌ 不支持 | ✅ 同名 interface 自动合并 |
| 描述联合/元组 | ✅ | ❌ |
Discriminated Union(判别联合)
联合类型中每个成员都包含一个相同的字面量属性(discriminant),TS 可以通过这个属性做精确的类型收敛。也叫 Tagged Union。
type Result =
| { status: 'ok'; data: string }
| { status: 'error'; message: string }
function handle(result: Result) {
if (result.status === 'ok') {
console.log(result.data) // 收敛为第一个成员
} else {
console.log(result.message) // 收敛为第二个成员
}
}Exhaustiveness Check(详尽性检查)
配合 never 类型,确保联合类型的所有分支都被处理到。当后续新增了联合成员但忘记处理时,TS 会在编译期报错。
function handle(result: Result) {
switch (result.status) {
case 'ok': return result.data
case 'error': return result.message
default:
const _exhaustive: never = result // 如果 Result 新增了成员,这里会报错
return _exhaustive
}
}Covariance & Contravariance(协变与逆变)
描述泛型类型在子类型关系中的变化方向。
- 协变(Covariant):子类型关系"方向一致"。函数返回值是协变的:如果
Cat是Animal的子类型,那么() => Cat也是() => Animal的子类型。 - 逆变(Contravariant):子类型关系"方向相反"。函数参数是逆变的:
(animal: Animal) => void是(cat: Cat) => void的子类型。
type AnimalFn = (a: Animal) => void
type CatFn = (c: Cat) => void
// 参数逆变:接受更宽泛参数的函数,可以赋给接受更具体参数的变量在 TS 中,函数参数默认是双变(bivariant)的,开启
strictFunctionTypes后才会严格按逆变处理。
Declaration Merging(声明合并)
同名的 interface、namespace 等声明,TS 会自动将它们合并为一个类型。常用于为第三方库扩展类型定义。
interface User {
name: string
}
interface User {
age: number
}
// 合并后等价于 { name: string; age: number }
const user: User = { name: 'xiaoming', age: 18 }Conditional Types(条件类型)
语法类似三元表达式,根据类型关系返回不同的类型。
type IsString<T> = T extends string ? 'yes' : 'no'
type A = IsString<string> // 'yes'
type B = IsString<number> // 'no'Infer(类型推断关键字)
在条件类型中使用 infer 关键字,从类型中"提取"出一个子类型。ReturnType、Parameters 等内置工具类型底层都依赖 infer。
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never
type Fn = () => string
type Result = ReturnType<Fn> // stringMapped Types(映射类型)
遍历已有类型的属性,生成一个新类型,语法为 [K in keyof T]。Partial、Required、Readonly 等工具类型都是映射类型。
type Optional<T> = {
[K in keyof T]?: T[K]
}
// 等价于内置的 Partial<T>Template Literal Types(模板字面量类型)
用模板字符串语法操作字符串字面量类型,可以做类型级别的字符串拼接。
type EventName = 'click' | 'focus' | 'blur'
type Handler = `on${Capitalize<EventName>}`
// 'onClick' | 'onFocus' | 'onBlur'Ambient Declaration(环境声明)
使用 declare 关键字声明一个类型或变量,告诉 TS "这个东西在运行时存在,但不由我来提供实现"。常见于 .d.ts 文件中。
// 声明一个全局变量,不提供实现
declare const __VERSION__: string
// 声明一个模块
declare module '*.svg' {
const content: string
export default content
}Type Predicate(类型谓词)
函数返回值为 arg is SomeType 形式,告诉 TS 当函数返回 true 时,参数就是该类型。是实现自定义类型守卫的方式。
function isString(val: unknown): val is string {
return typeof val === 'string'
}
function print(val: string | number) {
if (isString(val)) {
console.log(val.toUpperCase()) // val 被收敛为 string
}
}Index Signature(索引签名)
描述一个对象可以用任意 key 访问,同时指定 key 和 value 的类型。
interface StringMap {
[key: string]: string
}
const map: StringMap = { name: 'xiaoming', city: 'beijing' }Branded Types(品牌类型)
通过给类型附加一个虚构属性来模拟名义类型,防止结构相同但语义不同的类型被混用。
type UserId = string & { readonly __brand: 'UserId' }
type OrderId = string & { readonly __brand: 'OrderId' }
function getUser(id: UserId) {}
const orderId = '123' as OrderId
getUser(orderId) // ❌ 类型不匹配,即使底层都是 string
