因为这几个TypeScript代码的坏习惯,同事被罚了500块
作者:Daniel Bartholomae
翻译:疯狂的技术宅
原文链接:https://startup-cto.net/10-bad-typescript-habits-to-break-this-year/
近几年 TypeScript 和 JavaScript 一直在稳步发展。我们在过去写代码时养成了一些习惯,而有些习惯却没有什么意义。以下是我们都应该改正的 10 个坏习惯。
1.不使用 strict 模式
这种习惯看起来是什么样的
没有用严格模式编写 tsconfig.json。
{"compilerOptions": {"target": "ES2015","module": "commonjs"}
}
应该怎样
只需启用 strict 模式即可:
{"compilerOptions": {"target": "ES2015","module": "commonjs","strict": true}
}
为什么会有这种坏习惯
在现有代码库中引入更严格的规则需要花费时间。
为什么不该这样做
更严格的规则使将来维护代码时更加容易,使你节省大量的时间。
2. 用 || 定义默认值
这种习惯看起来是什么样的
使用旧的 || 处理后备的默认值:
function createBlogPost (text: string, author: string, date?: Date) {return {text: text,author: author,date: date || new Date()}
}
应该怎样
使用新的 ?? 运算符,或者在参数重定义默认值。
function createBlogPost (text: string, author: string, date: Date = new Date())return {text: text,author: author,date: date}
}
为什么会有这种坏习惯
?? 运算符是去年才引入的,当在长函数中使用值时,可能很难将其设置为参数默认值。
为什么不该这样做
?? 与 || 不同,?? 仅针对 null 或 undefined,并不适用于所有虚值。
3. 随意使用 any 类型
这种习惯看起来是什么样的
当你不确定结构时,可以用 any 类型。
async function loadProducts(): Promise<Product[]> {const response = await fetch('https://api.mysite.com/products')const products: any = await response.json()return products
}
应该怎样
把你代码中任何一个使用 any 的地方都改为 unknown
async function loadProducts(): Promise<Product[]> {const response = await fetch('https://api.mysite.com/products')const products: unknown = await response.json()return products as Product[]
}
为什么会有这种坏习惯
any 是很方便的,因为它基本上禁用了所有的类型检查。通常,甚至在官方提供的类型中都使用了 any。例如,TypeScript 团队将上面例子中的 response.json() 的类型设置为 Promise <any>。
为什么不该这样做
它基本上禁用所有类型检查。任何通过 any 进来的东西将完全放弃所有类型检查。这将会使错误很难被捕获到。
4. val as SomeType
这种习惯看起来是什么样的
强行告诉编译器无法推断的类型。
async function loadProducts(): Promise<Product[]> {const response = await fetch('https://api.mysite.com/products')const products: unknown = await response.json()return products as Product[]
}
应该怎样
这正是 Type Guard 的用武之地。
function isArrayOfProducts (obj: unknown): obj is Product[] {return Array.isArray(obj) && obj.every(isProduct)
}function isProduct (obj: unknown): obj is Product {return obj != null&& typeof (obj as Product).id === 'string'
}async function loadProducts(): Promise<Product[]> {const response = await fetch('https://api.mysite.com/products')const products: unknown = await response.json()if (!isArrayOfProducts(products)) {throw new TypeError('Received malformed products API response')}return products
}
为什么会有这种坏习惯
从 JavaScript 转到 TypeScript 时,现有的代码库通常会对 TypeScript 编译器无法自动推断出的类型进行假设。在这时,通过 as SomeOtherType 可以加快转换速度,而不必修改 tsconfig 中的设置。
为什么不该这样做
Type Guard 会确保所有检查都是明确的。
5. 测试中的 as any
这种习惯看起来是什么样的
编写测试时创建不完整的用例。
interface User {id: stringfirstName: stringlastName: stringemail: string
}test('createEmailText returns text that greats the user by first name', () => {const user: User = {firstName: 'John'} as anyexpect(createEmailText(user)).toContain(user.firstName)
}
应该怎样
如果你需要模拟测试数据,请将模拟逻辑移到要模拟的对象旁边,并使其可重用。
interface User {id: stringfirstName: stringlastName: stringemail: string
}class MockUser implements User {id = 'id'firstName = 'John'lastName = 'Doe'email = 'john@doe.com'
}test('createEmailText returns text that greats the user by first name', () => {const user = new MockUser()expect(createEmailText(user)).toContain(user.firstName)
}
为什么会有这种坏习惯
在给尚不具备广泛测试覆盖条件的代码编写测试时,通常会存在复杂的大数据结构,但要测试的特定功能仅需要其中的一部分。短期内不必关心其他属性。
为什么不该这样做
在某些情况下,被测代码依赖于我们之前认为不重要的属性,然后需要更新针对该功能的所有测试。
6. 可选属性
这种习惯看起来是什么样的
将属性标记为可选属性,即便这些属性有时不存在。
interface Product {id: stringtype: 'digital' | 'physical'weightInKg?: numbersizeInMb?: number
}
应该怎样
明确哪些组合存在,哪些不存在。
interface Product {id: stringtype: 'digital' | 'physical'
}interface DigitalProduct extends Product {type: 'digital'sizeInMb: number
}interface PhysicalProduct extends Product {type: 'physical'weightInKg: number
}
为什么会有这种坏习惯
将属性标记为可选而不是拆分类型更容易,并且产生的代码更少。它还需要对正在构建的产品有更深入的了解,并且如果对产品的设计有所修改,可能会限制代码的使用。
为什么不该这样做
类型系统的最大好处是可以用编译时检查代替运行时检查。通过更显式的类型,能够对可能不被注意的错误进行编译时检查,例如确保每个 DigitalProduct 都有一个 sizeInMb。
7. 用一个字母通行天下
这种习惯看起来是什么样的
用一个字母命名泛型
function head<T> (arr: T[]): T | undefined {return arr[0]
}
应该怎样
提供完整的描述性类型名称。
function head<Element> (arr: Element[]): Element | undefined {return arr[0]
}
为什么会有这种坏习惯
这种写法最早来源于C++的范型库,即使是 TS 的官方文档也在用一个字母的名称。它也可以更快地输入,只需要简单的敲下一个字母 T 就可以代替写全名。
为什么不该这样做
通用类型变量也是变量,就像其他变量一样。当 IDE 开始向我们展示变量的类型细节时,我们已经慢慢放弃了用它们的名称描述来变量类型的想法。例如我们现在写代码用 const name ='Daniel',而不是 const strName ='Daniel'。同样,一个字母的变量名通常会令人费解,因为不看声明就很难理解它们的含义。
8. 对非布尔类型的值进行布尔检查
这种习惯看起来是什么样的
通过直接将值传给 if 语句来检查是否定义了值。
function createNewMessagesResponse (countOfNewMessages?: number) {if (countOfNewMessages) {return `You have ${countOfNewMessages} new messages`}return 'Error: Could not retrieve number of new messages'
}
应该怎样
明确检查我们所关心的状况。
function createNewMessagesResponse (countOfNewMessages?: number) {if (countOfNewMessages !== undefined) {return `You have ${countOfNewMessages} new messages`}return 'Error: Could not retrieve number of new messages'
}
为什么会有这种坏习惯
编写简短的检测代码看起来更加简洁,使我们能够避免思考实际想要检测的内容。
为什么不该这样做
也许我们应该考虑一下实际要检查的内容。例如上面的例子以不同的方式处理 countOfNewMessages 为 0 的情况。
9. ”棒棒“运算符
这种习惯看起来是什么样的
将非布尔值转换为布尔值。
function createNewMessagesResponse (countOfNewMessages?: number) {if (!!countOfNewMessages) {return `You have ${countOfNewMessages} new messages`}return 'Error: Could not retrieve number of new messages'
}
应该怎样
明确检查我们所关心的状况。
function createNewMessagesResponse (countOfNewMessages?: number) {if (countOfNewMessages !== undefined) {return `You have ${countOfNewMessages} new messages`}return 'Error: Could not retrieve number of new messages'
}
为什么会有这种坏习惯
对某些人而言,理解 !! 就像是进入 JavaScript 世界的入门仪式。它看起来简短而简洁,如果你对它已经非常习惯了,就会知道它的含义。这是将任意值转换为布尔值的便捷方式。尤其是在如果虚值之间没有明确的语义界限时,例如 null、undefined 和 ''。
为什么不该这样做
与很多编码时的便捷方式一样,使用 !! 实际上是混淆了代码的真实含义。这使得新开发人员很难理解代码,无论是对一般开发人员来说还是对 JavaScript 来说都是新手。也很容易引入细微的错误。在对“非布尔类型的值”进行布尔检查时 countOfNewMessages 为 0 的问题在使用 !! 时仍然会存在。
10. != null
这种习惯看起来是什么样的
棒棒运算符的小弟 ! = null使我们能同时检查 null 和 undefined。
function createNewMessagesResponse (countOfNewMessages?: number) {if (countOfNewMessages != null) {return `You have ${countOfNewMessages} new messages`}return 'Error: Could not retrieve number of new messages'
}
应该怎样
明确检查我们所关心的状况。
function createNewMessagesResponse (countOfNewMessages?: number) {if (countOfNewMessages !== undefined) {return `You have ${countOfNewMessages} new messages`}return 'Error: Could not retrieve number of new messages'
}
为什么会有这种坏习惯
如果你的代码在 null 和 undefined 之间没有明显的区别,那么 != null 有助于简化对这两种可能性的检查。
为什么不该这样做
尽管 null 在 JavaScript早期很麻烦,但 TypeScript 处于 strict 模式时,它却可以成为这种语言中宝贵的工具。一种常见模式是将 null 值定义为不存在的事物,将 undefined 定义为未知的事物,例如 user.firstName === null 可能意味着用户实际上没有名字,而 user.firstName === undefined 只是意味着我们尚未询问该用户(而 user.firstName === 的意思是字面意思是 '' 。
点击关注,第一时间了解华为云新鲜技术~
因为这几个TypeScript代码的坏习惯,同事被罚了500块相关推荐
- TypeScript 代码整洁之道
中文 | English 将 Clean Code 的概念适用到 TypeScript,灵感来自 clean-code-javascript. 本文翻译自 labs42io/clean-code-ty ...
- java十进制小数转化为二进制小数代码 乘二取整法_(四)改掉这些坏习惯,还怕写不出健壮的代码?...
Code Review 是一场苦涩但有意思的修行. (一)改掉这些坏习惯,还怕写不出健壮的代码? (二)改掉这些坏习惯,还怕写不出优雅的代码? (三)改掉这些坏习惯,还怕写不出优雅的代码? 书接上篇, ...
- python程序员一天写多少行代码-程序员写Python时的5个坏习惯,你有几条?
很多文章都有介绍怎么写好 Python,我今天呢,相反,说说写代码时的几个坏习惯.有的习惯会让 Bug 变得隐蔽难以追踪,当然,也有的并没有错误,只是个人觉得不够优雅. 注意:示例代码在 Python ...
- 【重构】 代码的坏味道总结 Bad Smell (一) (重复代码 | 过长函数 | 过大的类 | 过长参数列 | 发散式变化 | 霰弹式修改)
膜拜下 Martin Fowler 大神 , 开始学习 圣经 重构-改善既有代码设计 . 代码的坏味道就意味着需要重构, 对代码的坏味道了然于心是重构的比要前提; . 作者 : 万境绝尘 转载请注明出 ...
- Angular Component TypeScript代码和最后转换生成的JavaScript代码比较
TypeScript代码使用@Component定义一个Component: @Component({selector: 'app-shipping',templateUrl: './shipping ...
- 重构 改善既有代码的设计:代码的坏
以下内容来自<<重构 改善既有代码的设计>> 一.什么是重构 所谓重构(Refactoring)是这样一个过程:在不改变代码外在行为的前提下,对代码做出修改以改进程序的内部结构 ...
- 【重构之法】代码的坏味道
代码的坏味道 坏味道意指代码中出现的可以被改进的地方.当你嗅到坏味道的时候,也就意味着重构的时机到了. 重构就是对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修 ...
- 重构-改善既有的代码设计-------代码的坏味道
重构-改善既有的代码设计 代码的坏味道 神秘命名(Mysterious Name) 给函数.变量.模块和类命名时,要使它能清晰地表明自己的功能和用法,使得写下的代码直观明了. 常用重构手法为重命名,包 ...
- C#坏习惯:通过不好的例子学习如何制作好的代码——第5部分
目录 介绍 定义和历史 我如何理解OCP? 我如何理解OCP? 3个级别 当代码关闭时 预测未来和YAGNI 让我们编码 不好的例子 更好的方法 SOLID恰当的结合在一起 更多例子 修改或扩展 什么 ...
最新文章
- python3.6安装opencv-python3.6.5安装opencv3
- 用NiceTool在微信浏览器中下载APP
- 云大计算机专业录取分数线,2016年云南大学艺术类专业录取分数线
- ITK:图像的置换轴
- 系统工程师主要做什么_Filecoin运维工程师在做什么?
- 基于TableStore的海量电商订单元数据管理
- 参加技术培训前的辅导,选得对,学得好
- 我们渴望和平freeeim
- 1.3 编程基础之算术表达式与顺序执行(20题)
- Apache Flink 进阶(四):Flink on Yarn / K8s 原理剖析及实践
- 支付系统中人民银行支付系统(CNAPS)和中国银联下面的跨行支付系统是一回事儿吗?
- AD14简明使用教程(同样试用于手工制板)
- 计算机五笔教案ppt,计算机应用基础课件(五笔字型课件).ppt
- 拓展显示器分辨率模糊(亲测,超级有用)
- Chemoffice 2018安装教程
- 银行利息,活期,定期,本金知识集锦!
- tomcat安装不上
- 阿里淘系优质开源项目推荐(下)
- 进制之间的相互转换(超详细)
- EXT前端数据传不到后台