CD's blog CD's blog
首页
  • HTMLCSS
  • JavaScript
  • Vue
  • TypeScript
  • React
  • Node
  • Webpack
  • Git
  • Nestjs
  • 小程序
  • 浏览器网络
  • 学习笔记

    • 《TypeScript 从零实现 axios》
    • Webpack笔记
  • JS/TS教程

    • 《现代JavaScript》教程
🔧工具方法
  • 网站
  • 资源
  • Vue资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

CD_wOw

内卷的行情,到不了的梦
首页
  • HTMLCSS
  • JavaScript
  • Vue
  • TypeScript
  • React
  • Node
  • Webpack
  • Git
  • Nestjs
  • 小程序
  • 浏览器网络
  • 学习笔记

    • 《TypeScript 从零实现 axios》
    • Webpack笔记
  • JS/TS教程

    • 《现代JavaScript》教程
🔧工具方法
  • 网站
  • 资源
  • Vue资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • TypeScript类型梳理
  • TypeScript联合、交叉类型解读
  • TypeScript枚举用法解读
  • keyof用法梳理
    • 基础概述
    • keyof取值
    • keyof取对象值
    • keyof 取联合类型
    • keyof取交叉类型
  • extends用法梳理
  • type-challenges笔记
  • TypeScript笔记
CD_wOw
2022-09-03
目录

keyof用法梳理

做了type-challenges之后,记录对keyof的理解。

# 基础概述

运算符采用keyof对象类型并生成其键的字符串或数字文字联合。

type Point = { x: number; y: number };
type P = keyof Point // 'x'|'y';
1
2

如果该类型具有string或number索引签名,keyof则将返回这些类型:

type Arrayish = { [n: number]: unknown };
type A = keyof Arrayish;
//type A = number
    
 
type Mapish = { [k: string]: boolean };
type M = keyof Mapish;
// type M = string | number
1
2
3
4
5
6
7
8

type M 带有number类型的原因是我们在js书写对象过程中会将number类型的key自动转成string类型,所以在这里会默认带有number类型

# keyof取值

keyof 对于不同的类型将会得到不同的取值,这将关系到后续我们对keyof的理解。它会取到普通类型的原型链内的属性,对于复杂对象类型,会取到其键值。

  1. 使用 keyof 对 any 和 never 取值
keyof any; // string | number | symbol
keyof never; // string | number | symbol
1
2
  1. 使用 keyof 对 {}、unknown、undefined、null、object、 () => void 取值
keyof unknown; // never
keyof undefined; // never
keyof null; // never
keyof object; // never
keyof {}; // never
keyof (() => void); // never
1
2
3
4
5
6
  1. 使用 keyof 对 string 取值
keyof string;
// number | typeof Symbol.iterator | "toString" | "valueOf" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "length" | "substr" | "codePointAt" | "includes" | "endsWith" | "normalize" | "repeat" | "startsWith" | "anchor" | "big" | "blink" | "bold" | "fixed" | "fontcolor" | "fontsize" | "italics" | "link" | "small" | "strike" | "sub" | "sup"
1
2
  1. 使用 keyof 对 number 取值
keyof number; // "toString" | "toLocaleString" | "valueOf" | "toFixed" | "toExponential" | "toPrecision"
1
  1. 使用 keyof 对 symbol 取值
keyof symbol; // "toString" | "valueOf" | typeof Symbol.toPrimitive | typeof Symbol.toStringTag
1
  1. 使用 keyof 对 boolean 取值
keyof boolean; // "valueOf"
1

# keyof取对象值

keyof 某个对象类型,将会返回其对象类型内的键遍历,并将其作为联合类型返回

type Bar = {
  name: string;
  age: string;
  gender: number;
};
type K = keyof Bar; // 'name'|'age'|'gender'
1
2
3
4
5
6

遍历 Bar 接口的属性,将得到的值是 name gender 的联合类型

当我们keyof一个数组类型时,遍历的是数组的属性,得到的就是数组属性的联合类型:

type K2 = keyof Bar[]; // "length" | "push" | "pop" | "concat" | ...
1

# keyof 取联合类型

当keyof取联合类型值时,取得其实是联合类型内的公共键。举例说明:

type Z = keyof ("2" | 1); // type Z = "toString" | "valueOf"
1

我们从上文已经可以知道取“2” 即是取其string类型里的属性,1即取其number类型内的属性。当两者联合时, keyof取的每一个联合类型内的公共属性(或是键),这时string和number原型链上有着相同的两个方法"toString" | "valueOf"就被取了出来。

那当联合类型内的元素是对象又会是怎么样呢?

type Foo = {
  name: string;
  age: string;
  helo: string;
};
type Bar = {
  name: string;
  age: string;
  gender: number;
};

type W = keyof (Bar | Foo);
// type W = "name" | "age"
type K = keyof (Bar | Foo | "2");
// type K = never
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

我们可以看到,Foo对象和Bar对象中有着相同的属性name和age,根据上面所说的,keyof取的是联合类型共同的键,此时就会取出他们的公共属性name和age,并返回联合类型"name" | "age"。 当我们为其增加一个字符串“2”时,我们可以发现,三者之间不存在有相同的键了,所以keyof返回的是never。那么怎么样让他们都有相同的键呢,我们这样测试:

type Foo = {
  name: string;
  age: string;
  helo: string;
  toString: () => {};
};
type Bar = {
  name: string;
  age: string;
  gender: number;
  toString: () => {};
};
type K = keyof (Bar | Foo | "2"); // type K = "toString"
1
2
3
4
5
6
7
8
9
10
11
12
13

综上得出结论,keyof取的是联合类型共同的键

那么,keyof对于交叉类型取的又是什么呢?

# keyof取交叉类型

我们直接看例子:

type Foo = {
  name: string;
  age: string;
};
type Bar = {
  name: string;
  age: string;
  gender: number;
};

type a = keyof (Foo & Bar); // "name" | "age" | "gender"
type aa = keyof Foo | keyof Bar; // "name" | "age" | "gender"

type b = keyof (Foo | Bar); // "name" | "age"
type bb = keyof Foo & keyof Bar; // "name" | "age"
// 即 ('name' | 'age') & ('name'|'age'|'gender')

type c = Exclude<a, b>; // "gender"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

可以看到,Foo & Bar 之后得到的其实是一个新的共同拥有双方键的新对象,keyof的取值遵循 keyof 取对象值的规则,将其化为键的联合类型。

当我们去掉小括号,将其通过交叉类型合并也是如此。

编辑 (opens new window)
#TypeScript
上次更新: 2023/03/22, 15:28:00
TypeScript枚举用法解读
extends用法梳理

← TypeScript枚举用法解读 extends用法梳理→

最近更新
01
gsap动画库学习笔记 - 持续~
06-05
02
远程组件加载方案笔记
05-03
03
小程序使用笔记
03-29
更多文章>
Theme by Vdoing | Copyright © 2020-2023 CD | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式