TypeScript 基础类型

这一章系统讲 TS 内置的基础类型。它们大部分和 JS 的类型一一对应(string、number、boolean),但 TS 还多出了几个 JS 没有的类型(元组、never、unknown、enum)。掌握这些,你就能给绝大多数变量标上正确的类型。

1. 三个最基础的类型

JS 的三种原始类型,TS 全部支持,写法就是类型名小写:

// JS 的三种原始类型,TS 全部支持,一一对应
let str: string = "你好";
let num: number = 42;        // 整数、浮点都是 number
let bool: boolean = true;

// 字符串支持模板字符串(和 JS 一样)
const name = "小明";
const greeting: string = `你好, ${name}`;

注意类型名首字母小写string 不是 String。大写的 String 在 TS 里是另一个东西(JS 的包装对象类型),不要混用。

2. 数组

数组是最高频的数据结构。TS 有两种等价写法,推荐简写:

// 数组:两种等价写法
let scores: number[] = [90, 85, 88];
let tags: Array<string> = ["ts", "js"];

// 推荐用 number[] 这种简写,更直观
let matrix: number[][] = [    // 二维数组
  [1, 2, 3],
  [4, 5, 6],
];

// 联合类型的数组:元素可以是多种类型
let mixed: (string | number)[] = [1, "a", 2, "b"];

3. 元组(Tuple)—— TS 独有

元组是固定长度、固定顺序、各位置类型可以不同的数组。这是 JS 没有的类型,常用于"函数返回多个值"的场景:

// 元组(tuple):固定长度、固定顺序、各位置类型可不同的数组
let pair: [string, number] = ["小明", 20];
//      ^[0] 是 string       ^[1] 是 number

// 访问时,每个位置都有正确的类型
console.log(pair[0].toUpperCase());  // string 的方法
console.log(pair[1].toFixed(2));      // number 的方法

// ❌ 长度不对会报错
let bad: [string, number] = ["a", 1, 2];
// 报错:源具有 3 个元素,但目标仅允许 2 个

// 常见用途:函数返回多个值
function minmax(arr: number[]): [number, number] {
  return [Math.min(...arr), Math.max(...arr)];
}

元组和数组的区别:数组是"同类型任意长",元组是"异类型固定长"。初学阶段用得不多,但在约定数据结构时很有用。

4. null 与 undefined

在 TS 里,nullundefined 既是值也是类型。它们默认是所有类型的子类型(即 let x: number = null 不报错),但推荐开启 strictNullChecks——这样它们就只能赋给对应的类型,能挡住大量"忘了处理空值"的 bug:

// null 和 undefined:在 TS 里是独立的类型
let n: null = null;
let u: undefined = undefined;

// 默认(非严格模式)下,它们是所有类型的子类型
let x: number = null;   // 严格模式下会报错
// 但开启 strictNullChecks 后(推荐),必须显式联合
let y: number | null = null;   // 这才安全

5. void —— 函数无返回值

void 表示"没有返回值",几乎只用在函数的返回类型上:

// void:函数没有返回值
function log(msg: string): void {
  console.log(msg);
  // 没有 return,或 return undefined
}

// 声明一个 void 变量没意义,只能赋 undefined/null
let v: void = undefined;

6. never —— 永不返回

never 表示函数永远不会正常返回——要么抛异常,要么无限循环。它听起来抽象,但有个非常实用的用途:穷尽检查(确保 switch/if 把所有情况都处理了):

// never:永远不会到达的返回类型
// 1. 抛异常的函数
function fail(msg: string): never {
  throw new Error(msg);
}

// 2. 无限循环
function forever(): never {
  while (true) {}
}

// never 是所有类型的子类型,常用于穷尽检查
type Shape = "circle" | "square";
function area(s: Shape): number {
  switch (s) {
    case "circle": return 1;
    case "square": return 2;
    default:
      // 如果未来加了新成员,s 就不是 never,这里会报错
      const _: never = s;
      return _;
  }
}

上面 default 分支的 const _: never = s 是个套路:如果未来给 Shape 加了新成员(比如 "triangle")却忘了在 switch 里处理,TS 就会在这里报错,提醒你补上。这就是 never 的妙用。

7. any 与 unknown —— 谨慎使用

any 是 TS 的"逃生舱":它放弃所有类型检查,什么都能塞。尽量少用,因为用了等于白写 TS。如果真不知道类型,优先用 unknown——它是安全版的 any,接受任何值,但用之前必须先收窄:

// any:放弃类型检查,什么都能塞
let a: any = 10;
a = "hello";        // 不报错
a.toUpperCase();    // 不报错(运行时才崩)

// unknown:安全版的 any,用之前必须先收窄
let u: unknown = "hi";
// u.toUpperCase();  // ❌ 报错:对象的类型为 "unknown"
if (typeof u === "string") {
  console.log(u.toUpperCase());  // ✅ 收窄后才能用
}

养成"用 unknown 而不是 any"的习惯,能在很多地方挡住隐性 bug。

8. 枚举(enum)

枚举给一组相关的常量起友好的名字,让代码可读性更强。推荐用字符串枚举,调试时更直观:

// 枚举:给一组相关的常量起友好名字
enum Color {
  Red,      // 默认从 0 开始
  Green,    // 1
  Blue,     // 2
}
let c: Color = Color.Green;   // 值为 1

// 字符串枚举(更推荐,调试友好)
enum Status {
  Idle = "idle",
  Loading = "loading",
  Success = "success",
  Error = "error",
}
let s: Status = Status.Loading;   // "loading"

小结

TS 的基础类型包括:stringnumberboolean、数组(T[])、元组([A, B])、nullundefinedvoidneveranyunknownenum。其中 any 要少用,unknown 是它的安全替代。下一篇我们看 TS 最常用的对象描述工具——接口 interface

← 上一篇 TypeScript 变量

下一篇 TypeScript 接口

✈️💬