Skip to content

C33. 类型运算

3.1. 使用 &| 运算符创建新类型

类型运算符允许组合现有类型,构建更复杂的类型。

3.1.1. 联合类型(Union Types) |

语法Type1 | Type2 表示值可以是其中一种类型,需通过类型守卫确定具体类型。

typescript
// 示例:联合类型
let value: string | number;
value = "TypeScript";  // 合法
value = 42;            // 合法
value = true;          // ❌ 报错!类型不匹配

function logId(id: string | number) {
  if (typeof id === "string") {
    console.log(`ID是字符串: ${id}`);
  } else {
    console.log(`ID是数字: ${id}`);
  }
}

WARNING

联合类型需用 typeofinstanceof 或类型守卫缩小类型范围,否则无法调用特定方法(如 toUpperCase())。

3.1.2. 交叉类型(Intersection Types) &

语法Type1 & Type2 合并多个类型的属性,形成新类型。

typescript
interface Dog {
  bark(): void;
}

interface Bird {
  fly(): void;
}

type SuperPet = Dog & Bird;

const pet: SuperPet = {
  bark() { console.log("汪!") },
  fly() { console.log("飞走了!") }
};

3.2. 使用 ? 创建可选类型

在接口或类型中,用 ? 标记属性为可选

typescript
interface User {
  name: string;
  age?: number;  // 可选属性
}

const user1: User = { name: "Alice" };  // 合法
const user2: User = { name: "Bob", age: 30 };  // 合法
const user3: User = { };  // ❌ 必须提供 name

TIP

访问可选属性时建议使用可选链操作符?.):

typescript
console.log(user.age?.toString());  // 若 age 不存在,返回 undefined

3.3. 泛型(Generics)

泛型允许函数、接口或类操作“任意类型”,避免重复代码。

示例:泛型函数

typescript
// 泛型函数:返回传入的值
function identity<T>(arg: T): T {
  return arg;
}

const num = identity<number>(42);  // 显式指定类型参数
const str = identity("Hello");     // 类型推断自动推导为 string

泛型接口

typescript
interface GenericIdentity {
  <T>(arg: T): T;
}

const myIdentity: GenericIdentity = identity;

INFO

泛型参数名通常用单字母:T(Type)、K(Key)、U(Type Union)等。

3.4. 使用 extends 对泛型约束

通过 extends 限制泛型参数的类型,确保其具备特定属性。

typescript
// 约束为有 length 属性的类型
function logLength<T extends { length: number }>(arg: T): number {
  return arg.length;
}

logLength("TypeScript");  // 合法,返回 10
logLength([1, 2, 3]);    // 合法,返回 3
logLength(42);           // ❌ 报错!number 没有 length 属性

示例:约束为接口

typescript
interface HasId {
  id: number;
}

function processItem<T extends HasId>(item: T): T {
  item.id = 123;
  return item;
}

const user = processItem({ id: 1, name: "Alice" });  // 合法
const invalid = processItem({ name: "Bob" });        // ❌ 缺少 id 属性

3.5. 基础类型体操

通过组合类型运算符和泛型,实现灵活的类型操作。

示例:提取对象的键类型

typescript
type Keys = keyof { name: string; age: number };  // "name" | "age"

示例:映射类型(基础)

typescript
type PartialUser<T> = {
  [P in "name" | "age"]?: T;  // 将指定属性改为可选
};

type User = PartialUser<string>;  // { name?: string; age?: string }

WARNING

类型操作需遵循 TypeScript 的类型推断规则,避免因类型过于复杂导致编译错误。

知识回顾

核心要点

  1. 类型运算符
    • |:联合类型(值可为其中一种类型)。
    • &:交叉类型(合并多个类型的属性)。
    • ?:定义可选属性。
  2. 泛型
    • <T> 定义类型参数,实现类型复用。
    • extends 约束泛型参数的类型。
  3. 类型安全
    • 联合类型需用类型守卫缩小范围。
    • 泛型约束确保参数具备必要属性。
  4. 类型体操
    • 使用 keyof 提取属性名,通过映射类型自定义对象结构。

课后练习

  1. 单选题:以下哪个运算符用于创建交叉类型?

    • A. |
    • B. &
    • C. +
    • D. *
  2. 填空题:定义一个泛型函数 identity,其类型应为 <T>(arg: T) => T,代码为: function identity____(arg: T): T { return arg; }

  3. 代码纠错

    typescript
    interface Animal {
      name: string;
    }
    function showName(animal: Animal | null) {
      return animal.name;  // ❌ 报错!可能为 null
    }
  4. 综合题

    1. 定义一个接口 Rectangle,包含 widthheight 属性。
    2. 使用交叉类型创建 Square,合并 Rectangleside: number 属性。
    3. 编写一个泛型函数 getLength<T extends { length: number }>(arg: T),返回 arg.length
    4. 使用 extends 约束泛型,确保传入对象包含 id 属性。

Built by Vitepress | Apache 2.0 Licensed