文章目录加载中

Typescript-高级操作符

# const 断言

特点:

  • 字面量(数组、接口)类型变为 readonly
  • 字面量类型不能被扩展

举例:

不使用 const 断言:

const CONFIG_KEYS = ["name", "school", "country"];

type KEY_TYPES = typeof CONFIG_KEYS; // KEY_TYPES 是 string[]

type KEY_TYPE = typeof CONFIG_KEYS[number]; // KEY_TYPE 是 string

使用 const 断言,ts 推断更精确:

const CONST_CONFIG_KEYS = ["name", "school", "country"] as const;

type COPNST_KEY_TYPES = typeof CONST_CONFIG_KEYS; // COPNST_KEY_TYPES 是 readonly ["name", "school", "country"]

type CONST_KEY_TYPE = typeof CONST_CONFIG_KEYS[number]; // CONST_KEY_TYPE 是 "name" | "school" | "country"

# typoef 和 type

typeof 在 js 中,可以获得对象类型.

在 ts 中,能够配合 type 关键词,将对象类型保存在类型字面量中。

const CONFIG_KEYS = ["name", "school", "country"];

console.log(typeof CONFIG_KEYS); // 输出;object
type KEY_TYPES = typeof CONFIG_KEYS; // KEY_TYPES 是 string[]

# keyof

keyof 用来获取某种类型的所有键,注意不是某个变量。

例子:假设声明了一个 json 对象,然后想获取它的所有键的类型应该怎么办?

// 利用 const 断言,告诉解释器不能被扩展
const VARS = {
  NODE_ENV: "production",
  AUTHOR: "xintan"
} as const;
// 再获取它的类型
type VARS_TYPE = typeof VARS;
// 最后获取类型上的key的类型
type VARS_KEYS_TYPE = keyof VARS_TYPE; // "NODE_ENV" | "AUTHOR"

再来一个用例,比如断言Reflect.ownKeys()的返回结果的类型:

const obj = {
  name: "12yuanxin3",
  age: 22
} as const;

const objKeys = <(keyof typeof obj)[]>Reflect.ownKeys(obj); // objKeys 类型是: ("name" | "age")[]

# extends

基础的用法:可以用于 class 继承、interface 继承。

# 用法 1: T extends U ? X : Y

用法:T extends U ? X : Y。这个比较难理解,而且很常见。其实就是:如果 T 包含的类型是 U 包含的类型的 '子集',那么取结果 X,否则取结果 Y

举例:

type Diff<T, U> = T extends U ? never : T; // 找出T和U的差集
type Filter<T, U> = T extends U ? T : never; // 找出T和U的交集

# 用法 2: 范型约束

用法:<T extends Lengthwise>

举例:

interface Lengthwise {
  length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
  console.log(arg.length);
  return arg;
}

如果写成 function loggingIdentity<T>(arg: T): T,就会报错:T 上不存在 length 属性。正如所见,约束范型,传入的 arg 必须有 length 属性。

# infer

作用:针对 ts 推断的类型,声明一个字面量,在extends语句中使用。

举例:

// 获得函数的返回类型
// 首先,范型约束了 T 是传入的函数的类型
// 然后,利用 extends 扩展表达式 + infer,将函数返回类型设置为R
// 最后,因为对T进行了约束,所以表达式一定是 true,也就是一定返回 R
// 我的理解:第2和3步骤就是为了拿到函数返回类型
type ReturnType<T extends (...args: any) => any> = T extends (
  ...args: any
) => infer R
  ? R
  : any;

例子中的infer R就是传入参数(某个函数)的返回类型,在这个表达式中,函数的返回类型被R变量代替。

infer 使用的位置

infer 声明的这个变量只能在 true 分支中使用

# 反解 Promise

理解了 ReturnType,我写出了一个反解 Promise的 typescript 扩展类型:

type UnPromiseType<T extends (...args: any) => any> = T extends (
  ...args: any
) => Promise<infer U>
  ? U
  : never;

使用效果:

async function main(): Promise<string> {
  return "abc";
}

type returnTypeWithoutPromise = UnPromiseType<typeof main>; // returnTypeWithoutPromise 是 string

# 参考链接

本文来自心谭博客:xin-tan.com,经常更新web和算法的文章笔记,前往github查看目录归纳:github.com/dongyuanxin/blog