TS 中的 keyof 和 typeof 操作符

TypeScript keyof 操作符
使用object(key)获取对象属性时报错
Typescript - 类型操作符

keyof

keyof 用于遍历某种类型的属性(可以操作接口、类以及基本数据类型)
在 TS 中定义一个获取函数属性的函数如下:

function prop(obj: object, key: string) {return obj[key];
}

在上面代码中,为了避免调用 prop 函数时传入错误的参数类型,我们为 obj 和 key 参数设置了类型,分别为 {} 和 string 类型。然而,事情并没有那么简单。针对上述的代码,TypeScript 编译器会输出以下错误信息:

Element implicitly has an ‘any’ type because expression of type ‘string’ can’t be used to index type ‘{}’.

元素隐式地拥有 any 类型,因为 string 类型不能被用于索引 {} 类型。要解决这个问题,你可以使用以下非常暴力的方案:

function prop(obj: object, key: string) {return (obj as any)[key];
}

该函数用于获取某个对象中指定属性的属性值。因此我们期望用户输入的属性是对象上已存在的属性,那么如何限制属性名的范围呢?这时我们可以利用本文的主角 keyof 操作符:

function prop<T extends object, K extends keyof T>(obj: T, key: K) {return obj[key];
}

在以上代码中,我们使用了 TypeScript 的泛型和泛型约束。首先定义了 T 类型并使用 extends 关键字约束该类型必须是 object 类型的子类型,然后使用 keyof 操作符获取 T 类型的所有键,其返回类型是联合类型,最后利用 extends 关键字约束 K 类型必须为 keyof T 联合类型的子类型。

keyof 与对象的数值属性

在使用对象的数值属性时,我们也可以使用 keyof 关键字。请记住,如果我们定义一个带有数值属性的对象,那么我们既需要定义该属性,又需要使用数组语法访问该属性:

class ClassWithNumericProperty {[1]: string = "Semlinker";
}let classWithNumeric = new ClassWithNumericProperty();
console.log(`${classWithNumeric[1]} `);

下面我们来举个示例,介绍一下在含有数值属性的对象中,如何使用 keyof 操作符来安全地访问对象的属性:

enum Currency {CNY = 6,EUR = 8,USD = 10
}const CurrencyName = {[Currency.CNY]: "人民币",[Currency.EUR]: "欧元",[Currency.USD]: "美元"
};console.log(`CurrencyName[Currency.CNY] = ${CurrencyName[Currency.CNY]}`);
console.log(`CurrencyName[36] = ${CurrencyName[6]}`);

为了方便用户能根据货币类型来获取对应的货币名称,我们来定义一个 getCurrencyName 函数,具体实现如下:

function getCurrencyName<T, K extends keyof T>(key: K, map: T): T[K] {return map[key];
}console.log(`name = ${getCurrencyName(Currency.CNY, CurrencyName)}`);

同样,getCurrencyName 函数和前面介绍的 prop 函数一样,使用了泛型和泛型约束,从而来保证属性的安全访问。

typeof

typeof 操作符用于获取变量的类型。因此这个操作符的后面接的始终是一个变量,且需要运用到类型定义当中。为了方便大家理解,我们来举一个具体的示例:

type Person = {name: string;age: number;
}let man: Person = {name: "Semlinker",age: 30
}type Human = typeof man;

typeof 和 keyof 一起使用

const COLORS = {red: 'red',blue: 'blue'
}// 首先通过typeof操作符获取color变量的类型,然后通过keyof操作符获取该类型的所有键,
// 即字符串字面量联合类型 'red' | 'blue'
type Colors = keyof typeof COLORS
let color: Colors;
color = 'red' // Ok
color = 'blue' // Ok// Type '"yellow"' is not assignable to type '"red" | "blue"'.
color = 'yellow' // Error

如果直接 keyof 一个对象变量的话,获取到的并不是该对象的属性组成的联合类型,而会是该对象的方法及属性的联合类型,比如除了属性还会有 “valueOf” “toString” 等。

思考

最后留到思考题,有兴趣的小伙伴可以想一想:

interface StringIndexArray {[index: string]: string;
}interface NumberIndexArray {[index: number]: string;
}type K1 = keyof StringIndexArray // type K1 = string | number
type K2 = keyof NumberIndexArray // type K2 = number

Keyof inferring string | number when key is only a string

TS 中的 keyof 和 typeof 操作符相关推荐

  1. 【TS】1355- TS typeof 操作符原来有这 5 种用途!

    阿宝哥精心准备的<轻松学 TypeScript> 视频教程已经更新到第十八期了,合集播放量已达 13.3W+.通过形象生动的动画,让你轻松搞懂 TypeScript 的难点和核心知识点! ...

  2. 细数 TS 中那些奇怪的符号

    TypeScript 是一种由微软开发的自由和开源的编程语言.它是 JavaScript 的一个超集,而且本质上向这个语言添加了可选的静态类型和基于类的面向对象编程. 本文阿宝哥将分享这些年在学习 T ...

  3. 如何进阶TypeScript功底?一文带你理解TS中各种高级语法

    引言 TypeScript 的重要性我不在强调了,我相信仍然会有大多数前端开发者碰到复杂类型一概使用 any 处理. 我写这篇文章的目的就是为了让你告别 AnyScript ,文章告别晦涩的概念结合实 ...

  4. typeof操作符返回一个字符串,表示未经计算的操作数的类型。

    typeof操作符返回一个字符串,表示未经计算的操作数的类型. 语法 typeof运算符后跟操作数: typeof operand or typeof (operand) 参数 operand 是一个 ...

  5. vue+ts中引入组件自动提示 declare module

    在我们引入vant UI 组件库时 只要我们输入一个<van- 就会出来很多提示,只要你记得组件的单词或者字母,就可以直接使用,非常的方便. 它是如何实现的呢? 我们随便双击一个vant组件进入 ...

  6. TS复习-----TS中的函数

    目录 一.ts函数的定义 二.ts中定义函数传参 1.函数传参方法 2.可选参数 3.默认参数 4.剩余参数 函数重载 一.ts函数的定义 函数是一种特殊的对象,可以被调用.TS 里的函数和原生,ES ...

  7. typescript keyof 和 typeof 用法

    typeof 操作符可以用来获取一个变量或对象的类型 const states = {name: 1,block: () => {return '123'}, }同一个类型的数据,直接获取它的类 ...

  8. typeof操作符的返回值

    使用typeof操作符 对一个值使用typeof操作符可能返回下列某个字符串: 1):undefined--如果这个值未定义 2):boolean--如果这个值是布尔值 3):string--如果这个 ...

  9. C++中的new和delete操作符重载

    文章目录 1 new和delete操作符重载 1.1 new和delete操作符重载简介 1.2 静态存储区中创建动态对象 1.3 在指定的地址上创建C++对象 2 new[]和delete[]操作符 ...

  10. Ionic3在ts中获取html中值的方法

    我觉得有两种方法,都是Angular中的语法,一种是把值当做参数传递,另一种是使用ngModel实现双向绑定 还有一种很少用到的,Js的原生方法:document.getElementById('ch ...

最新文章

  1. mysql noinstall_windows mysql noinstall
  2. (转)数据库设计范式深入浅出
  3. 如何用python创建一个下载网站-如何写一个python脚本下载文件??
  4. 以太坊地址算法php,以太坊ETH源码分析(1):地址生成过程
  5. python numpy.mean() axis参数使用方法【sum(axis=*)是求和,mean(axis=*)是求平均值】
  6. 一个弹出页面的徐徐升起的js效果
  7. 网页上的文本不让你复制下载?老司机教你几招,轻松免费复制
  8. office visio连接线控制方法
  9. html跳转按钮谷歌浏览器点击没反应,网页打印的按钮无效,点击打印没有任何反映!求解!...
  10. 如何修改图片大小?图片怎么调整尺寸?
  11. 什么是“双重支付”,即“双花”
  12. git基础教程(11) git checkout命令,掌握这些足以
  13. 【小米商城】--类别展示,登出,注销商品详情展示
  14. 第六章 市场结构和企业--完全竞争
  15. 计算机软件专业可以考哪些证书
  16. 3个月周末,软考高级复习攻略,信息系统项目管理师考后总结
  17. nvme分区选mbr还是guid_怎么分辨硬盘是GUID格式还是MBR格式以及怎样更改
  18. 知乎上这个程序员火了,竟是因为给老板修了一 次U盘...
  19. Android简单适配9.0~12.0
  20. 合并表格文件的简单方法

热门文章

  1. 黑马程序员Netty全套教程,全网最全Netty深入浅出教程,Java网络编程的王者
  2. 使用accton进行进程会计处理
  3. 戴尔DELL OEM Win7SP1简体中文旗舰版原版光盘镜像64位
  4. XMOS 最新 USB 专业录音声卡解决方案
  5. ffmpeg时间戳计算
  6. UTC时区表(.Net)
  7. 虚拟机(vmware)linux中ctrl按键失灵 解决办法
  8. 5、判断是否为偶数(0106)
  9. 什么软件测试卡路里,热量表(计算热量的仪表)_百度百科
  10. socket写超时c语言,设置socket超时时间