草庐IT

TS进阶之keyof

JonnyLan 2024-01-30 原文

刷完了type-challenges的所有简单和中等难度的题目后,对TypeScript的类型操作有了一些新的理解和认识。特此用几篇文章来记录下一些重要的知识点。

本系列文章需要您对TypeScript有基本的了解

基本用法

JavaScript通过 Object.keys()获取对象的所有属性键值,而typescript主要关注的是类型操作,通过 keyof 操作符可以获取对象中的所有键类型组成的联合类型

为了具体了解keyof操作符的作用,我们通过一些例子来解释下:

type Person = {
  id: number;
  name: string;
  age: number;
};

type P1 = keyof Person; //'id' | 'name' | 'age'

keyof操作符得到的是Person类型的所有键值类型即 'id','name''age' 三个字面量类型组成的联合类型'id' | 'name' | 'age'

实际应用

接下来我会用一些例子讲解keyof的应用。

获取对象所有属性的类型
type P2 = Person[keyof Person];  // number | string
  1. Person['key']查询类型(Lookup Types), 可以获取到对应属性类型的类型;
  2. Person[keyof Person]本质上是执行 Person['id' | 'name' | 'age']
  3. 由于联合类型具有分布式的特性,Person['id' | 'name' | 'age'] 变成了 Person['id'] | Person['name'] | Person['age']
  4. 最后得到的结果就是 number | string.
约束范型参数的范围
type MyPick<T, K extends keyof T> = { [P in K]: T[P] };
type P3 = MyPick<Person, 'id' | 'age'>

  1. K extends keyof TK进行了约束,只能是'id','name','age'中的一个类型或者几个类型组成的联合类型;
  2. 如果没有这个约束,{ [P in K]: T[P] } 则会报错。
和映射类型组合实现某些功能
  • 给对象类型的所有属性加上readonly修饰符
type MyReadonly<T> = { readonly [P in keyof T]: T[P] };
type P4 = MyReadonly<Person>;  // { readonly id: number; readonly name: string; readonly age: number; }
  1. [P in keyof T]是对所有属性的键值类型进行遍历,案例中得到的P 分别是'id','name''age';
  2. T[P]是查询类型,上面介绍过了,Person['id'] 的结果是numberPerson['name'] 的结果是stringPerson['age'] 的结果是number
  3. 将每个属性类型添加readonly修饰符,最后的结果就是 { readonly id: number; readonly name: string; readonly age: number; }
  • 去掉对象类型的某些属性

微软官是通过Pickexclude组合来实现Omit逻辑的,我们可以通过以下的代码实现同样的功能。

type MyOmit<T, K> = { [P in keyof T as P extends K ? never : P]: T[P] };
type P5 = MyOmit<Person, 'id' | 'name'> // {age: number;}

代码中的as P extends K ? never : P这部分代码叫做重映射 ,因为我们不一定需要的是P,有些情况下需要对P进行一些转换;案例中K 中包含的P键值类型则通过never忽略了,相反则保留。所以最后的结果是{age: number;}

  • 给对象类型添加新的属性
type AppendToObject<T, U extends keyof any, V> = {[P in keyof T | U]: P extends keyof T ? T[P] : V}
type P6 = AppendToObject<Person, 'address', string> // { address: string; id: number; name: string; age: number; }
和条件类型组合实现功能
  • 两个对象类型合并成一个新的类型
type Merge<F extends Record<string, any>, S extends Record<string, any>> = {
  [P in keyof F | keyof S]: P extends keyof S ? S[P] : P extends keyof F ? F[P] : never;
};

type Skill = {
  run: () => void;
}

type P7 = Merge<Person, Skill>; // { id: number; name: string; age: number; run: () => void; }

案例中P extends keyof S ? X : Y 的部分叫做 条件类型(后面也会单独介绍)。代码中的含义就是如果 PF的属性类型,则取F[P],如果PS的属性类型,则取S[P]

小结

经过前面的介绍,应该对keyof的使用有一些感觉了。下面我列一些代码,大家可以感受下:

type _DeepPartial<T> = { [K in keyof T]?: _DeepPartial<T[K]> }
type Diff<T extends Record<string, any>, U extends Record<string, any>> = {
  [P in keyof U | keyof T as P extends keyof U
    ? P extends keyof T
      ? never
      : P
    : P extends keyof T
    ? P
    : never]: P extends keyof U ? U[P] : P extends keyof T ? T[P] : never;
};

这个实现逻辑涉及到了其他的知识点有点复杂,没完全看懂没关系,后面会介绍。

有关TS进阶之keyof的更多相关文章

  1. 大家沉迷短视频无法自拔?Python爬虫进阶,带你玩转短视频 - 2

    大家好,我是辣条。现在短视频可谓是一骑绝尘,吃饭的时候、休息的时候、躺在床上都在刷短视频,今天给大家带来python爬虫进阶:美拍视频地址加密解析。短视频js逆向解析抓取目标工具使用重点学习内容项目思路解析抓取目标目标网址:美拍视频工具使用开发环境:win10、python3.7开发工具:pycharm、Chrome工具包:requests、xpath、base64重点学习内容爬虫采集数据的解析过程js代码调试技巧js逆向解析代码Python代码的转换项目思路解析进入到网站的首页挑选你感兴趣的分类根据首页地址获取到进入详情页面的超链接的跳转地址找到对应加密的视频播放地址数据这个数据是静态的网页

  2. javascript - TS1148 ~ 如何使用 --module : "import" and typescript 2. x "none" - 2

    我目前正在使用一些旧版JavaScript开发一个项目。该应用程序不包含模块加载器,它只是将所有内容作为全局变量放入window对象中。遗憾的是,接触遗留代码并包含模块加载器对我来说不是一个可行的选择。我想在我自己的代码中使用typescript。我设置了typescript编译器选项module:"none"在我的tsconfig.json中,我只使用命名空间来组织我自己的代码。到目前为止效果很好。..到现在为止:import*asRxfrom'rxjs';..Rx.Observable.from(['foo',bar']);...//ResultsinTypeScript-Erro

  3. javascript - TS 编译 - "noImplicitAny"不起作用 - 2

    我有密码letz;z=50;z='z';我的tsconfig.json是:{"compilerOptions":{"target":"es5","module":"commonjs","sourceMap":false,"noEmitOnError":true,"strict":true,"noImplicitAny":true}}但是编译成js没有异常是什么鬼?最好的问候,克罗瓦 最佳答案 因为z永远不会被输入为any。z的类型只是根据您分配给它的内容进行推断。来自releasenotes:WithTypeScript2.1,in

  4. javascript - 我如何解决 'Property ' 宽度'在类型 'HTMLElement' 上不存在。'在 vscode 中使用//@ts-check 类型检查 Javascript(不是 Typescript)时? - 2

    在view.js文件中:constcanvas=document.getElementById('canvas');...export{canvas,};在main.js文件中:import*asviewfrom'../src/view.js';...xPosition:view.canvas.width/2,给我'属性'width'在类型'HTMLElement'上不存在。类型检查错误。我不知道如何进行,我对typescript的了解为零,而且程序是用javascript编写的。我读过的所有解决方案都需要使用typescript,这在这个例子中是没有用的。有什么办法可以消除这个错误吗

  5. javascript - typescript + moment.js : error TS2307: Cannot find module 'moment' - 2

    我正在开发一个网络应用程序,使用angular1.5、typescript2.4.0、moment:2.18.1和gulp进行项目组装。这是我的tsconfig.json:{"files":["src/app/main.ts","types/**/*.ts"],"compilerOptions":{"noImplicitAny":false,"target":"es2015","allowSyntheticDefaultImports":true}}在我的date-range-picker.component.ts中。我正在导入时刻库,正如maindocumentation中所建议的那

  6. 【JavaEE进阶】——第二节.Spring核心和设计思想 - 2

    文章目录前言一、Spring是什么?二、什么是容器?三、什么是IoC?3.1初始loC3.2举例解释loC3.3 SpringIoC思想的体现四、什么是DI?4.1DI的概念4.2 Ioc和DI的区别总结前言今天我们将进入到有关spring的认识当中,要使用它的前提就是要认识并熟悉它,上一节我们介绍了有关maven的配置,必须要配置完成后,才能完成我们后面的学习工作,让我们进入到今天的学习当中吧!!!!!!!!!一、Spring是什么?概念:我们通常所说的Spring指的是SpringFramework(Spring框架),它是⼀个开源框架,有着活跃⽽庞⼤的社区,这就是它之所以能⻓久不衰的原因

  7. javascript - 如何在 tsconfig.json 中排除以 '.spec.ts' 结尾的文件 - 2

    我试图在我的tsconfig.json中包含一些文件,但它包含了我不想包含的文件。从repo协议(protocol)(带有未编译的源代码)我试图包含以.ts结尾的文件,除了那些以.spec.ts结尾的.下面包含了我想要的文件,但是没有成功排除我不要的文件。"include":["node_modules/dashboard/**/*.ts"],"exclude":["node_modules/dashboard/**/*.spec.ts"],(然后)新的Unixglob模式/字符串,我需要一些来正确匹配和排除文件,然后如何将它们添加到配置中。 最佳答案

  8. 【C语言进阶】还说不会?一文带你全面掌握计算机预处理操作 - 2

    目录🍊前言🍊:🍈一、宏与函数🍈:        1.宏与函数对比:    2.宏与函数的命名约定:🍓二、预处理操作符🍓:    1.预处理操作符"#":    2.预处理操作符"##":🥝三、条件编译🥝:    1.简述条件编译指令:    2.常见条件编译指令:🍒总结🍒:🛰️博客主页:✈️銮同学的干货分享基地🛰️欢迎关注:👍点赞🙌收藏✍️留言🛰️系列专栏:💐【进阶】C语言学习            🧧  C语言学习🛰️代码仓库:🎉VS2022_C语言仓库    家人们更新不易,你们的👍点赞👍和⭐关注⭐真的对我真重要,各位路过的友友麻烦多多点赞关注,欢迎你们的私信提问,感谢你们的转发!    

  9. javascript - typescript 错误 : TS2304: Cannot find name '$' - 2

    声明x=$('#msgBox_'+scope.boxId).position().left;生成一个errorTS2304:Cannotfindname'$'尽管jquery和@types安装在node_modules文件夹中。我的tsconfig.json看起来像这样:{"compilerOptions":{"module":"commonjs","target":"es5","sourceMap":true,"moduleResolution":"node","declaration":true},"exclude":["node_modules"]}我该如何解决?

  10. javascript - 需要将 fabricjs.d.ts 与 TypeScript 结合使用的示例 - 2

    我在尝试转换为使用TypeScript的项目中使用fabricjs,但我不知道如何使用它。以前我会通过执行以下操作来创建自己的自定义对象:my.namespace.Control=fabric.util.createClass(fabric.Object,{id:"",type:'Control',color:"#000000",...});在我的新项目中,我安装了来自here的TypeDefinition文件。但我不知道我应该如何使用它?查看.d.ts文件,fabric.Object似乎不是函数,因此不允许传递给createClass,并且createClass本身返回void,因此

随机推荐