TS高级用法总结《二》

557 阅读2分钟

TS高级用法总结《二》

本文主要内容:typeof、条件类型

本文阅读时间大约为6分钟,请听笔者娓娓道来。

typeof 类型运算符

请注意 type 是类型别名

// Prints "string"
console.log(typeof "Hello world");

使用 typeof 会自动返回 类型,这对于基本类型并不十分有用,但是结合其他类型操作符,您可以使用 typeof 方便地表示许多模式。

function f() {
  return { x: 10, y: 3 };
}
type P = ReturnType<typeof f>;
// type P = {
//     x: number;
//     y: number;
// }

或者还可以通过 索引

type Person = { age: number; name: string; alive: boolean };
type Age = Person["age"];
// type Age = number

使用任意类型进行索引的另一个示例是使用 T 来获取数组元素的类型。我们可以把它和 typeof 结合起来,方便地捕获数组文字的元素类型:

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

type Person = typeof MyArray[T];    
// type Person = {
//     name: string;
//     age: number;
// }

type Age = typeof MyArray[T]["age"]; 
// type Age = number

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

条件类型

在大多数有用的程序的核心,我们必须根据输入做出决定。程序没有什么不同,但是考虑到值可以很容易地反省,这些决定也是基于输入的类型。条件类型帮助描述输入和输出类型之间的关系。

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

type Example1 = Dog extends Animal ? number : string;
// Dog 是继承自 Animal 
// type Example1 = number
 
type Example2 = RegExp extends Animal ? number : string;
// type Example2 = string

再如有个重载函数,看看咱么怎么通过这个条件类型去改写。createLabel 的重载描述了一个基于输入类型进行选择的 JavaScript 函数

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";
}

改写

type NameOrId<T extends number | string> = T extends number
  ? IdLabel
  : NameLabel;

// 我们可以使用该条件类型将重载简化为单个函数,而不需要重载
function createLabel<T extends number | string>(idOrName: T): NameOrId<T> {
  throw "unimplemented";
}
let a = createLabel("typescript");
// let a: NameLabel
let b = createLabel(2.8);
// let b: IdLabel
let c = createLabel(Math.random() ? "hello" : 42);
// let c: NameLabel | IdLabel

总结

条件类型这一部分,还有一些更高级的用法,但笔者认为,可以先把这篇文章的内容学懂,再去学更高级的。虽然平常可能用不到,但是当你阅读源码的时候,你就会体会类型约束带来的好处!

阅读 Vue3 源码,如果不知道 ts 的高级用法,你可能会别绕晕;但是,如果你是初次阅读源码,建议在社区内找一个“简单”版本学习,咳咳!

👍👍👍

推荐源码阅读从 mini-vue 开始:gitHub 仓库,实现了最简的 Vue 模型!