Typescript 类型文档学习第二天

172 阅读2分钟

索引类型

type Person = { age: number; name: string; alive: boolean };

// Age = number 获取 Person 中属性 age 的类型
type Age = Person["age"]; 

// keyof 获取 Person 中的所有属性key
type T2 = Person[keyof Person]; // T1 = string | number | boolean

// 获取属性 "alive" | "name" 的 类型
type AliveOrName = "alive" | "name";
type I3 = Person[AliveOrName]; // T1 = string | boolean
const MyArray = [
  { name: "Alice", age: 15 },
  { name: "Bob", age: 23 },
  { name: "Eve", age: 38 },
];

// number 的含义是获取MyArray 中的所有类型的集合
type Person1 = typeof MyArray[number]; // Person1 = {name: string, age: number}

const MyArray2 = [
  { name: "Alice", age: 15 },
  { name: "Bob", age: 23 },
  { name: "Eve", age: 38, alive: true },
];

type Person2 = typeof MyArray2[number]; // Person2 = {name: string, age: number, alive: boolean} | {name: string, age: number, alive?: boolean}

type Age1 = typeof MyArray[number]["age"]; // Age1 = number

type Age2 = Person["age"]; // Age2 = number

type alive = typeof MyArray[number]["alive"]; // 报错, 因为alive 可能不存在

条件判断

interface Animal {
  live(): void;
}

interface Dog extends Animal {
  woof(): void;
}

// 条件语句, 如果 Dog 继承 Animal的话,是number类型, 否则是 string
type Example1 = Dog extends Animal ? number : string; //Example1  = number

interface IdLabel {
  id: number /* some fields */;
}
interface NameLabel {
  name: string /* other fields */;
}

function createLabel(id: number): IdLabel;
function createLabel(name: string): NameLabel;
function createLabel(nameOrId: string | number): IdLabel | NameLabel;
function createLabel(nameOrId: string | number): IdLabel | NameLabel {
   throw "unimplemented";
 }

// 对上面的例子重构下
// <> 中的extends 是约束的意思,类型必须继承 number 或者 string,
// 后面的 extends 是用来做判断的, 如果 继承number 返回 IdLabel ,否则 NameLabel
type NameOrId<T extends number | string> = T extends number
  ? IdLabel
  : NameLabel;

function createLabel<T extends number | string>(nameOrId: T): NameOrId<T> {
  throw "unimplemented";
}

let a1 = createLabel("typescript"); // a1 = NameLabel

let b = createLabel(2.8); // b = IdLabel

let c = createLabel(Math.random() ? "hello" : 42); // c = NameLabel | IdLabel

条件类型约束

type MessageOf<T> = T["message"]; // 报错, message可能不存在在类型 T 中, 这里可以对其仅需约束

// unknown 的意思代表着不知道是什么类型,等待推断
type MessageOf1<T extends { message: unknown }> = T["message"];

interface Email {
  message: string;
}

// 这里message 的类型就是string
type EmailMessageContents = MessageOf<Email>;
interface Email {
  message: string;
}

interface Dog {
  bark(): void;
}

type EmailMessageContents = MessageOf<Email>; // EmailMessageContents = string

type DogMessageContents = MessageOf<Dog>; // DogMessageContents = never

// infer 我理解的意思是, 重新定义一个类型
type Flatten<Type> = Type extends Array<infer Item> ? Item : Type;

// type 符合是一个 函数, 并且这个函数有返回值的话, 返回函数的返回值, 否则返回  never
type GetReturnType<Type> = Type extends (...args: never[]) => infer Return
  ? Return
  : never;

type Num = GetReturnType<() => number>; // Num = number

type Str = GetReturnType<(x: string) => string>; // Str = string

type Bools = GetReturnType<(a: boolean, b: boolean) => boolean[]>; // Bools = boolean[]

// 注意区别

type ToArray<Type> = Type extends any ? Type[] : never;

type StrArrOrNumArr = ToArray<string | number>; // StrArrOrNumArr = string[] | number[]

type ToArrayNonDist<Type> = [Type] extends [any] ? Type[] : never;

// 'StrArrOrNumArr' is no longer a union.
type StrArrOrNumArr2 = ToArrayNonDist<string | number>; // StrArrOrNumArr2 = (string | number) []

映射类型


// - 移除 readonly
type CreateMutable<Type> = {
  -readonly [Property in keyof Type]: Type[Property];
};

type LockedAccount = {
  readonly id: string;
  readonly name: string;
};

type UnlockedAccount = CreateMutable<LockedAccount>; // UnlockedAccount = {id: string; name: string;}

// - 去掉 ? 号
type Concrete<Type> = {
  [Property in keyof Type]-?: Type[Property];
};

type MaybeUser = {
  id: string;
  name?: string;
  age?: number;
};

type User = Concrete<MaybeUser>; // User = {id: string; name: string; age: number;}

// 通过 as 重新映射

// Events 约束 必须继承  { kind: string }
// E in Events , E 值的是传入的类型, 这里指的是 SquareEvent 、 CircleEvent
//
type EventConfig<Events extends { kind: string }> = {
  [E in Events as E["kind"]]: (event: E) => void;
};

type SquareEvent = { kind: "square"; x: number; y: number };
type CircleEvent = { kind: "circle"; radius: number };

type Config = EventConfig<SquareEvent | CircleEvent>;
// config = {
//   square = (event: SquareEvent) => void
//   circle = (event: CircleEvent) =>  void
// }

模板文字类型

type PropEventSource<Type> = {
  on(
    eventName: `${string & keyof Type}Changed`,
    callback: (newValue: any) => void
  ): void;
};

declare function makeWatchedObject<Type>(
  obj: Type
): Type & PropEventSource<Type>;

const person = makeWatchedObject({
  firstName: "Saoirse",
  lastName: "Ronan",
  age: 26,
});

person.on("firstNameChanged", (newValue) => {
  console.log(`firstName was changed to ${newValue}!`);
});

person.on("firstNameChanged", () => {});


person.on("firstNameChange", () => {}); // 报错, 约束了 on 事件的名称