Skip to content
第 11 章 前端 ⏱ 10 分钟阅读

第 11 章:类型推导 ​

学习目标 ​

  • 理解 TS 的"上下文类型推导"
  • 学会利用推导减少显式注解
  • 掌握常见场景的最佳类型推导
  • 避开 any 蔓延导致的推导失败

一、最佳公共类型推导 ​

typescript
// 多元素数组,推导为联合
const arr = [1, 'Tom', true];   // (string | number | boolean)[]

// 指定类型可优化
const arr2: (number | string)[] = [1, 'Tom'];

二、上下文类型(Contextual Typing) ​

typescript
// window.onmousedown 的类型由 onmousedown 的签名推导
window.onmousedown = (e) => {
  console.log(e.button);  // ✅ e 已被推导为 MouseEvent
};

// 函数参数
type F = (x: number) => string;
const f: F = (x) => x.toString();  // x 推导为 number

⚠️ 坑 1:箭头函数赋给有类型的变量时,参数类型会自动推导;但写成 function 不会。

typescript
type F = (x: number) => void;
const f1: F = (x) => console.log(x);   // ✅ x: number
const f2: F = function (x) { console.log(x); };  // ✅ x: number

三、字面量类型推导 ​

typescript
// let 推导为宽类型
let x = 'tom';   // string
x = 'jerry';     // ✅

// const 推导为字面量类型
const y = 'tom'; // 'tom'(字面量)

为什么? const 不可变,所以 TS 把它推导为最精确的字面量。

四、类型拓宽 vs 类型缩小 ​

typescript
// 类型拓宽
let a = 'hello';          // string(可重新赋任意字符串)
const b = 'hello';        // 'hello'(字面量)

// 对象
const obj = { x: 1 };     // { x: number }
obj.x = 99;               // ✅

// 数组字面量
const arr = [1, 2];       // number[]

五、常见推导场景 ​

函数返回值 ​

typescript
function add(a: number, b: number) {
  return a + b;   // 推断 number
}

解构 ​

typescript
const user = { id: 1, name: 'Tom' };
const { id, name } = user;   // id: number, name: string

async 函数 ​

typescript
async function fetchUser(): Promise<User> {
  const res = await fetch('/api/user');
  return res.json();   // ⚠️ 实际是 Promise<any>
}

⚠️ 坑 2:不加 schema 校验,res.json() 永远是 Promise<any>,需要在外部校验(用 zod / io-ts / yup)。

六、控制流推导 ​

typescript
function process(value: string | number): string {
  if (typeof value === 'string') {
    return value.toUpperCase();  // ✅ 收窄为 string
  }
  return value.toFixed(2);       // ✅ 收窄为 number
}

赋值与重新收窄:

typescript
let x: string | number = 'tom';
if (Math.random() > 0.5) {
  x = 123;   // x 变为 number
}
x.toUpperCase();  // ❌ x 可能是 number

七、显式标注的反例 ​

不要过度标注,推导已经够用:

typescript
// ❌ 多余
const num: number = 5;
const arr: number[] = [1, 2, 3];

// ✅ 利用推导
const num = 5;
const arr = [1, 2, 3];

八、ReturnType / Parameters 工具类型 ​

typescript
function getUser() {
  return { id: 1, name: 'Tom' };
}

type R = ReturnType<typeof getUser>;     // { id: number; name: string }
type P = Parameters<typeof getUser>;     // []

⚠️ 坑 3:typeof 取的是值的类型,所以 typeof getUser 拿到的是函数类型,再用 ReturnType 拆返回值。

九、本章小结 ​

要点关键
最佳公共类型数组元素类型合并为联合
上下文类型函数表达式参数由被赋值位置推导
字面量推导const 推到字面量,let 推到宽类型
控制流typeof / in / instanceof 收窄类型
显式标注只在必要地方写(参数、无初值、联合)
ReturnType从函数推导返回值类型

动手练习 ​

  1. 推导 vs 标注:const arr = [1, 2, 3] 的类型是什么?改 const arr: (number | string)[] 后呢?
  2. 上下文类型:写一个事件回调 (e: MouseEvent) => void,看看参数能不能省略类型
  3. ReturnType 实战:用 ReturnType<typeof fetch> 取出 fetch 的返回类型

下一章:第 12 章:类型守卫 →

本站基于 VitePress 构建 · 由 StackHub 团队维护