TypeScript 基础类型

TypeScript 的类型系统是其核心特性,理解基础类型是掌握 TypeScript 的第一步。


原始类型

TypeScript 支持 JavaScript 的所有原始类型,并提供类型注解。

基本原始类型

// 字符串
let name: string = "TypeScript";
 
// 数字(整数和浮点数统一为 number)
let age: number = 25;
let price: number = 99.99;
 
// 布尔值
let isActive: boolean = true;
 
// BigInt(ES2020+)
let bigNumber: bigint = 100n;
 
// Symbol
let sym: symbol = Symbol("key");

null 和 undefined

// 默认情况下,null 和 undefined 是所有类型的子类型
let u: undefined = undefined;
let n: null = null;
 
// 开启 strictNullChecks 后,需要显式处理
let value: string | null = null;
value = "hello";

数组类型

两种定义数组的方式:

// 方式一:类型[]
let numbers: number[] = [1, 2, 3];
let names: string[] = ["Alice", "Bob"];
 
// 方式二:Array<类型>(泛型语法)
let scores: Array<number> = [100, 95, 88];
 
// 只读数组
let readonlyArr: readonly number[] = [1, 2, 3];
// readonlyArr.push(4); // 错误:只读数组不能修改

元组(Tuple)

元组是固定长度和类型的数组。

// 基本元组
let tuple: [string, number] = ["hello", 42];
 
// 访问元素
console.log(tuple[0]); // "hello"
console.log(tuple[1]); // 42
 
// 可选元素
let optionalTuple: [string, number?] = ["hello"];
 
// 剩余元素
let restTuple: [string, ...number[]] = ["hello", 1, 2, 3];
 
// 只读元组
let readonlyTuple: readonly [string, number] = ["hello", 42];
 
// 命名元组(TypeScript 4.0+)
type NamedTuple = [name: string, age: number];
let person: NamedTuple = ["Alice", 25];

枚举(Enum)

枚举用于定义一组命名常量。

数字枚举

enum Direction {
  Up,      // 0
  Down,    // 1
  Left,    // 2
  Right    // 3
}
 
// 使用
let dir: Direction = Direction.Up;
 
// 可以指定起始值
enum Status {
  Pending = 1,
  Active,    // 2
  Completed  // 3
}

字符串枚举

enum Color {
  Red = "RED",
  Green = "GREEN",
  Blue = "BLUE"
}
 
let color: Color = Color.Red;
console.log(color); // "RED"

const 枚举

编译时会被内联,不生成额外代码:

const enum HttpStatus {
  OK = 200,
  NotFound = 404,
  ServerError = 500
}
 
let status = HttpStatus.OK; // 编译后直接变成 200

特殊类型

any

放弃类型检查,谨慎使用:

let anything: any = 42;
anything = "hello";
anything = true;
anything.foo.bar; // 不会报错,但运行时可能出错

unknown

类型安全的 any,使用前必须进行类型检查:

let value: unknown = "hello";
 
// 直接使用会报错
// console.log(value.length); // 错误
 
// 必须先检查类型
if (typeof value === "string") {
  console.log(value.length); // 正确
}
 
// 或使用类型断言
console.log((value as string).length);

void

表示没有返回值:

function log(message: string): void {
  console.log(message);
}
 
// void 类型变量只能赋值 undefined
let v: void = undefined;

never

表示永不返回的类型:

// 抛出异常
function throwError(message: string): never {
  throw new Error(message);
}
 
// 无限循环
function infiniteLoop(): never {
  while (true) {}
}
 
// 用于穷尽检查
type Shape = "circle" | "square";
 
function getArea(shape: Shape): number {
  switch (shape) {
    case "circle":
      return Math.PI * 10 * 10;
    case "square":
      return 10 * 10;
    default:
      const _exhaustive: never = shape;
      return _exhaustive;
  }
}

对象类型

object 类型

表示非原始类型:

let obj: object = { name: "Alice" };
obj = [1, 2, 3]; // 数组也是对象
// obj = "hello"; // 错误:string 不是 object

对象字面量类型

let user: { name: string; age: number } = {
  name: "Alice",
  age: 25
};
 
// 可选属性
let config: { url: string; timeout?: number } = {
  url: "https://api.example.com"
};
 
// 只读属性
let point: { readonly x: number; readonly y: number } = {
  x: 10,
  y: 20
};
// point.x = 30; // 错误:只读属性不能修改

字面量类型

// 字符串字面量
let direction: "left" | "right" = "left";
 
// 数字字面量
let dice: 1 | 2 | 3 | 4 | 5 | 6 = 3;
 
// 布尔字面量
let success: true = true;
 
// 结合使用
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
function request(url: string, method: HttpMethod) {
  // ...
}

类型断言

告诉编译器你比它更了解类型:

// 方式一:as 语法(推荐)
let value: unknown = "hello";
let length = (value as string).length;
 
// 方式二:尖括号语法(JSX 中不可用)
let length2 = (<string>value).length;
 
// 双重断言(谨慎使用)
let num = "hello" as unknown as number;
 
// const 断言
let arr = [1, 2, 3] as const; // readonly [1, 2, 3]
let obj = { name: "Alice" } as const; // { readonly name: "Alice" }

最佳实践

  1. 优先使用 unknown 而非 any:保持类型安全
  2. 避免过度使用类型断言:让 TypeScript 自动推断
  3. 使用 const 枚举:减少运行时开销
  4. 启用 strictNullChecks:避免空值错误
  5. 使用字面量类型:提供更精确的类型约束

typescript 类型 基础