TypeScript 联合类型入门:一个变量多种可能

前面写过类型标注入门,变量都有了固定类型。但现实里很多值不止一种可能:接口返回的可能是字符串也可能是 null,参数既接受数字也接受字符串。这时候就该联合类型(union type)出场了,写法是用竖线 | 把类型隔开。

基本用法:竖线隔开多个类型

let id: string | number;

id = 101;        // 正确
id = "A101";     // 正确
// id = true;    // 报错:boolean 不在联合里

function printId(value: string | number) {
  console.log("当前 id 是:" + value);
}

printId(101);      // 输出: 当前 id 是:101
printId("A101");   // 输出: 当前 id 是:A101

string | number 的意思是:这个位置要么是字符串,要么是数字,别的都不行。比起写成 any,联合类型把可能的范围说清楚了,超出照样报错。

类型收窄:先判断,再使用

联合类型的变量不能直接用某一类型的专属方法,因为类型系统不确定当前到底是哪个:

function len(value: string | number) {
  // return value.toUpperCase(); // 直接调用会报错
  if (typeof value === "string") {
    return value.toUpperCase();  // 这里已知是 string
  }
  return value.toString();       // 走到这里只剩 number
}

console.log(len("abc")); // 输出: ABC
console.log(len(1024));  // 输出: "1024"

typeof 判断之后,if 分支里 TypeScript 就确认了它是 string,专属方法随便用。这个缩小范围的过程叫类型收窄(narrowing)。收窄方式不止 typeof,instanceof、in、甚至 !== undefined 的判断都算。

字面量类型:把取值限定成几个固定值

竖线两边也可以直接写字面量,用来表达"只允许这几个值":

type Direction = "up" | "down" | "left" | "right";

function move(dir: Direction) {
  console.log("向 " + dir + " 移动");
}

move("up");       // 正确
// move("top");   // 报错:拼错单词当场拦下

let status: "loading" | "success" | "error" = "loading";
status = "success";  // 正确

这种写法在表示状态、开关、方向时特别好用,比随便传一个字符串安全得多——写错了编辑器直接划红线。

可空类型:类型 | null

最常见的联合其实是"正常值或空":

function findUser(name: string): string | null {
  if (name === "雪梨") {
    return "找到了";
  }
  return null; // 没找到时返回 null
}

const result = findUser("路人甲");
if (result !== null) {
  console.log(result.toUpperCase()); // 收窄后才能放心调用
}

先把可能为 null 的情况挡掉,后面的代码才能放心用,这正是联合类型帮我们养成的习惯。

小结

  • 联合类型用 | 连接,表示"若干类型之一",比 any 精确得多
  • 用之前先收窄:typeof / instanceof / in / 判空都行,收窄后才能调用专属方法
  • 字面量联合 "a" | "b" 适合限定状态和选项
  • 类型 | null 是最常见的联合,先判空再使用

把手里的 any 参数换成确切的联合类型,是给老代码补类型最划算的一步。