第三章:基本类型

TypeScript 拥有丰富的类型系统,本章将深入讲解基本数据类型,包括原始类型、数组、元组等。理解这些基础类型是掌握 TypeScript 类型系统的关键。

布尔类型只有两种值:true 和 false。

let isDone: boolean = false;
let isActive: boolean = true;
let hasPermission: boolean = true;
 
// 通过表达式赋值
let isGreater: boolean = 5 > 3;  // true
let isEqual: boolean = "hello" === "world";  // false
 
// 布尔对象(不推荐)
let boolObject: Boolean = new Boolean(true);  // 包装对象
let boolPrimitive: boolean = true;  // 原始类型,推荐

TypeScript 中所有数字都是浮点数,支持十进制、十六进制、二进制和八进制字面量。

// 十进制
let decimal: number = 42;
let float: number = 3.14159;
let negative: number = -10;
 
// 十六进制
let hex: number = 0xff;      // 255
let hex2: number = 0xABC;    // 2748
 
// 二进制
let binary: number = 0b1010;  // 10
let binary2: number = 0b11110000;
 
// 八进制
let octal: number = 0o744;  // 484
 
// 特殊数值
let infinity: number = Infinity;
let notANumber: number = NaN;
 
// 科学计数法
let scientific: number = 1.5e10;   // 15000000000
let small: number = 1.5e-10;
 
// 下划线分隔符(ES2021+)
let million: number = 1_000_000;
let binaryWithSep: number = 0b1111_0000;
// 单引号
let singleQuote: string = 'Hello';
 
// 双引号
let doubleQuote: string = "World";
 
// 模板字符串(推荐)
let name: string = "Alice";
let greeting: string = `Hello, ${name}!`;
let multiLine: string = `
  This is a
  multi-line string
`;
 
// 模板字符串支持表达式
let a: number = 5;
let b: number = 10;
let result: string = `The sum is ${a + b}`;
 
// 字符串方法
let str: string = "TypeScript";
let upper: string = str.toUpperCase();      // "TYPESCRIPT"
let lower: string = str.toLowerCase();      // "typescript"
let length: number = str.length;            // 10
let substring: string = str.substring(0, 4); // "Type"
let includes: boolean = str.includes("Script");  // true

Symbol 是 ES6 引入的原始数据类型,表示唯一的标识符。

// 创建 Symbol
const sym1: symbol = Symbol();
const sym2: symbol = Symbol("description");
const sym3: symbol = Symbol("description");
 
// 每个 Symbol 都是唯一的
console.log(sym2 === sym3);  // false
 
// 作为对象属性键
const id: symbol = Symbol("id");
const user = {
  [id]: 12345,
  name: "Alice"
};
 
// 获取 Symbol 属性需要使用 Object.getOwnPropertySymbols
console.log(Object.getOwnPropertySymbols(user));  // [Symbol(id)]
 
// Well-known Symbols
const iterator: symbol = Symbol.iterator;
const asyncIterator: symbol = Symbol.asyncIterator;
const hasInstance: symbol = Symbol.hasInstance;

BigInt 用于表示任意精度的整数,适合处理超出 number 安全整数范围的数值。

// 创建 BigInt
const big1: bigint = 9007199254740991n;
const big2: bigint = BigInt(9007199254740991);
const big3: bigint = BigInt("900719925474099199999");
 
// 运算
const sum: bigint = big1 + big2;
const product: bigint = big1 * 2n;
const power: bigint = 2n ** 100n;
 
// 比较
const isEqual: boolean = big1 === big2;
const isGreater: boolean = big1 > 0n;
 
// 注意:BigInt 和 number 不能直接混合运算
// const invalid = big1 + 5;  // Error
const valid = big1 + 5n;  // OK
 
// 转换
const numFromBig: number = Number(big1);  // 可能丢失精度
const strFromBig: string = big1.toString();

any 是最灵活的类型,可以赋值为任何类型,绕过类型检查。

let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false;
notSure = { name: "Alice" };
notSure = [1, 2, 3];
 
// 可以访问任何属性
notSure.ifItExists();
notSure.toFixed();
 
// 隐式 any
// 在 noImplicitAny 关闭时,未注解的变量默认为 any
function log(message) {  // 参数类型隐式为 any
  console.log(message);
}
 
// 明确的 any 使用场景
// 1. 第三方库没有类型定义
let thirdPartyData: any = fetchLegacyData();
 
// 2. 动态内容
let dynamicContent: any = JSON.parse(jsonString);
 
// 3. 逐步迁移项目
// 可以先用 any,再逐步添加类型

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

let notSure: unknown = 4;
notSure = "hello";
notSure = true;
 
// 不能直接使用
// notSure.toFixed();  // Error: Object is of type 'unknown'
 
// 必须使用类型检查
if (typeof notSure === "number") {
  console.log(notSure.toFixed(2));  // OK
}
 
if (typeof notSure === "string") {
  console.log(notSure.toUpperCase());  // OK
}
 
// 类型断言
const value: unknown = "hello";
const str: string = value as string;
 
// 使用类型守卫函数
function isString(value: unknown): value is string {
  return typeof value === "string";
}
 
if (isString(notSure)) {
  console.log(notSure.length);  // OK,TypeScript 知道是 string
}

never 表示永远不会发生的值,用于:

  1. 抛出异常的函数
  2. 无限循环的函数
  3. exhaustive type checking
// 抛出错误的函数返回 never
function throwError(message: string): never {
  throw new Error(message);
}
 
// 无限循环
function infiniteLoop(): never {
  while (true) {
    console.log("Looping...");
  }
}
 
// exhaustive checking
function assertNever(x: never): never {
  throw new Error("Unexpected object: " + x);
}
 
type Shape = 
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number }
  | { kind: "triangle"; base: number; height: number };
 
function getArea(shape: Shape): number {
  switch (shape.kind) {
    case "circle":
      return Math.PI * shape.radius ** 2;
    case "square":
      return shape.side ** 2;
    case "triangle":
      return (shape.base * shape.height) / 2;
    default:
      return assertNever(shape);  // 如果 Shape 新增类型,这里会报错
  }
}

void 表示没有返回值,通常用于函数。

// 无返回值的函数
function logMessage(message: string): void {
  console.log(message);
}
 
function processData(data: unknown): void {
  // 处理数据,不返回结果
  saveToDatabase(data);
}
 
// void 类型的变量只能赋值 undefined 或 null
let unusable: void = undefined;
// unusable = null;  // 在 strictNullChecks 下可能报错
 
// 实际上 void 类型的变量很少使用
// undefined
let u: undefined = undefined;
 
// null
let n: null = null;
 
// strictNullChecks 开启时的区别
let str: string = "hello";
// str = null;      // Error
// str = undefined; // Error
 
let nullableStr: string | null = null;  // OK
nullableStr = "hello";  // OK
 
let optionalStr: string | undefined = undefined;  // OK
optionalStr = "hello";  // OK
 
// 非空断言(谨慎使用)
function getLength(str: string | null): number {
  return str!.length;  // ! 告诉 TypeScript str 不为 null
}
 
// 更安全的做法
function getLengthSafe(str: string | null): number {
  return str ? str.length : 0;
}
// 类型[] 语法
let numbers: number[] = [1, 2, 3, 4, 5];
let strings: string[] = ["a", "b", "c"];
let booleans: boolean[] = [true, false, true];
 
// Array<类型> 语法(泛型)
let numbers2: Array<number> = [1, 2, 3];
let strings2: Array<string> = ["a", "b", "c"];
 
// 混合类型数组(不推荐)
let mixed: (string | number)[] = ["a", 1, "b", 2];
 
// 对象数组
interface User {
  id: number;
  name: string;
}
 
let users: User[] = [
  { id: 1, name: "Alice" },
  { id: 2, name: "Bob" }
];
 
// 多维数组
let matrix: number[][] = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
];
 
let threeDArray: number[][][] = [[[1, 2]], [[3, 4]]];
const numbers: number[] = [1, 2, 3, 4, 5];
 
// 不改变原数组的方法
const doubled: number[] = numbers.map(n => n * 2);
const evens: number[] = numbers.filter(n => n % 2 === 0);
const sum: number = numbers.reduce((a, b) => a + b, 0);
const found: number | undefined = numbers.find(n => n > 3);
const hasEven: boolean = numbers.some(n => n % 2 === 0);
const allPositive: boolean = numbers.every(n => n > 0);
const index: number = numbers.findIndex(n => n === 3);
const sliced: number[] = numbers.slice(1, 3);
 
// 改变原数组的方法
const arr: number[] = [1, 2, 3];
arr.push(4);        // 添加元素到末尾
arr.pop();          // 移除末尾元素
arr.unshift(0);     // 添加元素到开头
arr.shift();        // 移除开头元素
arr.splice(1, 1);   // 删除/插入元素
arr.sort((a, b) => b - a);  // 排序
arr.reverse();      // 反转
// 使用 readonly 修饰符
const readonlyNumbers: readonly number[] = [1, 2, 3];
// readonlyNumbers.push(4);  // Error
// readonlyNumbers[0] = 0;   // Error
 
// 使用 ReadonlyArray 泛型
const readonlyStrings: ReadonlyArray<string> = ["a", "b"];
 
// 使用 Readonly 工具类型
interface Config {
  settings: Readonly<number[]>;
}
 
// 只读数组可以赋值给普通数组
const arr: readonly number[] = [1, 2, 3];
// const mutable: number[] = arr;  // Error
 
// 普通数组可以赋值给只读数组
const mutable: number[] = [1, 2, 3];
const readonly2: readonly number[] = mutable;  // OK
// 自动推断
const numbers = [1, 2, 3];           // number[]
const strings = ["a", "b"];          // string[]
const mixed = [1, "a", true];        // (string | number | boolean)[]
 
// 空数组推断为 any[]
const empty = [];  // any[]
// 应该显式声明类型
const emptyNumbers: number[] = [];
 
// 使用 as const 得到字面量类型
const tuple = [1, 2, 3] as const;    // readonly [1, 2, 3]
const config = {
  ports: [3000, 8080] as const
};

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

// 定义元组
let person: [string, number] = ["Alice", 25];
 
// 顺序必须匹配
// let wrong: [string, number] = [25, "Alice"];  // Error
 
// 长度必须匹配
// person.push("extra");  // 可以编译,但类型系统不限制
// person[2];  // Error: Tuple type '[string, number]' of length '2' has no element at index '2'
 
// 可选元素
let optionalTuple: [string, number?] = ["Alice"];
optionalTuple = ["Alice", 25];  // OK
 
// 剩余元素
let restTuple: [string, ...number[]] = ["scores", 85, 90, 95];
// 使用类型别名
type Point = [x: number, y: number];
const point: Point = [10, 20];
 
// 或使用接口(更推荐)
interface Point2 {
  x: number;
  y: number;
}
const point2: Point2 = { x: 10, y: 20 };
 
// 具名元组元素(TypeScript 4.0+)
type RGB = [red: number, green: number, blue: number];
const color: RGB = [255, 128, 0];
// 元组解构
const point: [number, number] = [10, 20];
const [x, y] = point;
 
// 函数返回元组
function getUserInfo(): [string, number] {
  return ["Alice", 25];
}
 
const [name, age] = getUserInfo();
 
// 交换变量
let a = 1, b = 2;
[a, b] = [b, a];
 
// 忽略元素
const [first, , third] = [1, 2, 3];
// 只读元组
const readonlyTuple: readonly [string, number] = ["Alice", 25];
// readonlyTuple[0] = "Bob";  // Error
 
// 使用 Readonly 工具类型
type ReadonlyPoint = Readonly<[number, number]>;

枚举在第四章会详细介绍,这里简单了解其作为基本类型的特性。

// 数字枚举
enum Direction {
  Up,      // 0
  Down,    // 1
  Left,    // 2
  Right    // 3
}
 
// 字符串枚举
enum Color {
  Red = "RED",
  Green = "GREEN",
  Blue = "BLUE"
}
 
// 使用
const dir: Direction = Direction.Up;
const color: Color = Color.Red;
 
// 常量枚举(编译时内联)
const enum Status {
  Active = 1,
  Inactive = 0
}
// ✓ 函数参数和返回值
function calculate(x: number, y: number): number {
  return x + y;
}
 
// ✓ 对象属性
interface User {
  name: string;
  age: number;
}
 
// ✓ 复杂类型
const config: { apiUrl: string; timeout: number } = {
  apiUrl: "https://api.example.com",
  timeout: 5000
};
 
// ✓ 空数组
const numbers: number[] = [];
 
// ✓ 类属性
class Person {
  name: string;
  age: number;
}
// ✓ 简单变量初始化
const name = "Alice";        // string
const age = 25;              // number
const isActive = true;       // boolean
 
// ✓ 从函数返回值推断
const result = calculate(1, 2);  // number
 
// ✓ 数组字面量
const colors = ["red", "green", "blue"];  // string[]
 
// ✓ 对象字面量(简单情况)
const point = { x: 0, y: 0 };  // { x: number; y: number }
// 子类型可以赋值给父类型
let num: number = 10;
let biggerNum: 10 = 10;
num = biggerNum;  // OK
// biggerNum = num;  // Error
 
// 字面量类型
let exact: "hello" = "hello";
let general: string = exact;  // OK
// exact = general;  // Error
// 元组是数组的子类型
const tuple: [string, number] = ["a", 1];
const arr: (string | number)[] = tuple;  // OK
 
// 长度不兼容
// const tuple2: [string, number] = arr;  // Error
 
// 数组协变
let strings: string[] = ["a", "b"];
let objects: object[] = strings;  // OK(协变)
// 为复杂类型创建别名
type Point = [number, number];
type Point3D = [number, number, number];
 
type StringOrNumber = string | number;
type ID = string | number;
 
type Callback = (error: Error | null, result?: string) => void;
// 使用 as const 创建只读字面量类型
const config = {
  host: "localhost",
  port: 3000,
  debug: true
} as const;
 
// config.port = 8080;  // Error: Cannot assign to 'port'
 
// 数组常量断言
const roles = ["admin", "user", "guest"] as const;
type Role = typeof roles[number];  // "admin" | "user" | "guest"

本章我们学习了:

1. 原始类型 - boolean、number、string、symbol、bigint 2. 特殊类型 - any、unknown、never、void、null、undefined 3. 数组类型 - 声明方式、方法、只读数组 4. 元组类型 - 固定长度数组、命名元组 5. 类型选择 - 何时添加类型注解,何时依赖推断

分析以下代码中变量的推断类型:

const a = 42;
const b = "hello";
const c = [1, 2, 3];
const d = [1, "two", true];
const e = null;
const f = undefined;
const g = { x: 10, y: 20 };
const h = [1, 2] as const;

参考答案

const a: number = 42;
const b: string = "hello";
const c: number[] = [1, 2, 3];
const d: (string | number | boolean)[] = [1, "two", true];
const e: null = null;
const f: undefined = undefined;
const g: { x: number; y: number } = { x: 10, y: 20 };
const h: readonly [1, 2] = [1, 2] as const;

完成以下数组操作函数的类型定义和实现:

// 1. 过滤出数组中的偶数
function filterEven(numbers: number[]): number[] {
  // 实现
}
 
// 2. 计算数组中所有数字的和
function sumArray(numbers: number[]): number {
  // 实现
}
 
// 3. 将字符串数组转换为大写
function toUpperCaseArray(strings: string[]): string[] {
  // 实现
}
 
// 4. 找出一个数字数组中的最大值和最小值,返回元组
function findMinMax(numbers: number[]): [number, number] {
  // 实现
}

参考答案

// 1. 过滤偶数
function filterEven(numbers: number[]): number[] {
  return numbers.filter(n => n % 2 === 0);
}
 
// 2. 计算总和
function sumArray(numbers: number[]): number {
  return numbers.reduce((sum, n) => sum + n, 0);
}
 
// 3. 转换大写
function toUpperCaseArray(strings: string[]): string[] {
  return strings.map(s => s.toUpperCase());
}
 
// 4. 找最大最小值
function findMinMax(numbers: number[]): [number, number] {
  if (numbers.length === 0) {
    throw new Error("Array is empty");
  }
  let min = numbers[0];
  let max = numbers[0];
  for (const n of numbers) {
    if (n < min) min = n;
    if (n > max) max = n;
  }
  return [min, max];
}
 
// 或使用内置方法
function findMinMax2(numbers: number[]): [number, number] {
  return [Math.min(...numbers), Math.max(...numbers)];
}

实现一个类型安全的 parseValue 函数:

type ParsedValue = string | number | boolean | null;
 
function parseValue(input: unknown): ParsedValue {
  // 实现:根据 input 的实际类型返回相应的值
  // - 如果是 string,直接返回
  // - 如果是 number,直接返回
  // - 如果是 boolean,直接返回
  // - 如果是 null 或 undefined,返回 null
  // - 如果是其他类型,返回 null
}

参考答案

type ParsedValue = string | number | boolean | null;
 
function parseValue(input: unknown): ParsedValue {
  if (typeof input === "string") {
    return input;
  }
  if (typeof input === "number") {
    return input;
  }
  if (typeof input === "boolean") {
    return input;
  }
  if (input === null || input === undefined) {
    return null;
  }
  return null;
}
 
// 测试
console.log(parseValue("hello"));    // "hello"
console.log(parseValue(42));         // 42
console.log(parseValue(true));       // true
console.log(parseValue(null));       // null
console.log(parseValue(undefined));  // null
console.log(parseValue({}));         // null

实现以下类型转换函数:

interface Point {
  x: number;
  y: number;
}
 
// 1. 将 Point 对象转换为元组 [x, y]
function pointToTuple(point: Point): [number, number] {
  // 实现
}
 
// 2. 将元组 [x, y] 转换为 Point 对象
function tupleToPoint(tuple: [number, number]): Point {
  // 实现
}
 
// 3. 交换元组中的两个元素
function swap<T, U>(tuple: [T, U]): [U, T] {
  // 实现
}

参考答案

interface Point {
  x: number;
  y: number;
}
 
// 1. 对象转元组
function pointToTuple(point: Point): [number, number] {
  return [point.x, point.y];
}
 
// 2. 元组转对象
function tupleToPoint(tuple: [number, number]): Point {
  const [x, y] = tuple;
  return { x, y };
}
 
// 3. 交换元组元素
function swap<T, U>(tuple: [T, U]): [U, T] {
  const [first, second] = tuple;
  return [second, first];
}
 
// 测试
const point: Point = { x: 10, y: 20 };
const tuple = pointToTuple(point);  // [10, 20]
const backToPoint = tupleToPoint(tuple);  // { x: 10, y: 20 }
const swapped = swap(["hello", 42]);  // [42, "hello"]

该主题尚不存在

您访问的页面并不存在。如果允许,您可以使用创建该页面按钮来创建它。

  • typescript/第三章_基本类型.txt
  • 最后更改: 2026/03/09 15:22
  • 张叶安