<返回目录     Powered by claud/xia兄

第7课: 高级类型

联合类型 (Union Types)

联合类型表示一个值可以是几种类型之一,使用 | 分隔:

function padLeft(value: string, padding: string | number) {
  if (typeof padding === "number") {
    return Array(padding + 1).join(" ") + value;
  }
  if (typeof padding === "string") {
    return padding + value;
  }
  throw new Error(`Expected string or number, got '${padding}'.`);
}

padLeft("Hello", 4);
padLeft("Hello", ">>> ");

交叉类型 (Intersection Types)

交叉类型将多个类型合并为一个类型,使用 & 连接:

interface Person {
  name: string;
}

interface Contact {
  phone: string;
}

type Employee = Person & Contact;

let employee: Employee = {
  name: "Alice",
  phone: "123-456-7890"
};

类型别名 (Type Aliases)

type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;

function getName(n: NameOrResolver): Name {
  if (typeof n === "string") {
    return n;
  } else {
    return n();
  }
}

// 类型别名也可以是泛型
type Container = { value: T };

// 类型别名可以引用自己
type Tree = {
  value: T;
  left?: Tree;
  right?: Tree;
};

字面量类型

// 字符串字面量类型
type Easing = "ease-in" | "ease-out" | "ease-in-out";

function animate(dx: number, dy: number, easing: Easing) {
  // ...
}

animate(0, 0, "ease-in");
animate(0, 0, "uneasy"); // 错误

// 数字字面量类型
function rollDice(): 1 | 2 | 3 | 4 | 5 | 6 {
  return (Math.floor(Math.random() * 6) + 1) as 1 | 2 | 3 | 4 | 5 | 6;
}

索引类型 (Index Types)

function pluck(o: T, propertyNames: K[]): T[K][] {
  return propertyNames.map(n => o[n]);
}

interface Car {
  manufacturer: string;
  model: string;
  year: number;
}

let taxi: Car = {
  manufacturer: "Toyota",
  model: "Camry",
  year: 2014
};

let makeAndModel: string[] = pluck(taxi, ["manufacturer", "model"]);
let modelYear = pluck(taxi, ["model", "year"]);

映射类型 (Mapped Types)

type Readonly = {
  readonly [P in keyof T]: T[P];
};

type Partial = {
  [P in keyof T]?: T[P];
};

interface Person {
  name: string;
  age: number;
}

type ReadonlyPerson = Readonly;
type PartialPerson = Partial;

条件类型 (Conditional Types)

T extends U ? X : Y

// 示例
type TypeName =
  T extends string ? "string" :
  T extends number ? "number" :
  T extends boolean ? "boolean" :
  T extends undefined ? "undefined" :
  T extends Function ? "function" :
  "object";

type T0 = TypeName; // "string"
type T1 = TypeName<"a">; // "string"
type T2 = TypeName; // "boolean"

分布式条件类型

type Diff = T extends U ? never : T;
type Filter = T extends U ? T : never;

type T1 = Diff<"a" | "b" | "c", "a" | "e">; // "b" | "c"
type T2 = Filter void), Function>; // () => void

infer关键字

在条件类型中推断类型:

type ReturnType = T extends (...args: any[]) => infer R ? R : any;

function f() {
  return { x: 10, y: 3 };
}

type P = ReturnType; // { x: number; y: number; }

模板字面量类型

type World = "world";
type Greeting = `hello ${World}`; // "hello world"

type EmailLocaleIDs = "welcome_email" | "email_heading";
type FooterLocaleIDs = "footer_title" | "footer_sendoff";

type AllLocaleIDs = `${EmailLocaleIDs | FooterLocaleIDs}_id`;
// "welcome_email_id" | "email_heading_id" | "footer_title_id" | "footer_sendoff_id"
类型别名 vs 接口:
练习:
  1. 创建一个联合类型,表示HTTP方法(GET、POST、PUT、DELETE)
  2. 使用交叉类型合并两个接口
  3. 创建一个类型别名,表示树形结构
  4. 使用条件类型创建一个工具类型,提取数组元素类型