共计 6281 个字符,预计需要花费 16 分钟才能阅读完成。
作者:Daniel Bartholomae
翻译:疯狂的技术宅
原文:https://startup-cto.net/10-ba…
近几年 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: string
firstName: string
lastName: string
email: string
}
test('createEmailText returns text that greats the user by first name', () => {
const user: User = {firstName: 'John'} as any
expect(createEmailText(user)).toContain(user.firstName)
}
应该怎么
如果你须要模仿测试数据,请将模仿逻辑移到要模仿的对象旁边,并使其可重用。
interface User {
id: string
firstName: string
lastName: string
email: 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: string
type: 'digital' | 'physical'
weightInKg?: number
sizeInMb?: number
}
应该怎么
明确哪些组合存在,哪些不存在。
interface Product {
id: string
type: '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 ===
的意思是字面意思是 ''
。
本文首发微信公众号:前端先锋
欢送扫描二维码关注公众号,每天都给你推送陈腐的前端技术文章
欢送持续浏览本专栏其它高赞文章:
- 深刻了解 Shadow DOM v1
- 一步步教你用 WebVR 实现虚拟现实游戏
- 13 个帮你进步开发效率的古代 CSS 框架
- 疾速上手 BootstrapVue
- JavaScript 引擎是如何工作的?从调用栈到 Promise 你须要晓得的所有
- WebSocket 实战:在 Node 和 React 之间进行实时通信
- 对于 Git 的 20 个面试题
- 深刻解析 Node.js 的 console.log
- Node.js 到底是什么?
- 30 分钟用 Node.js 构建一个 API 服务器
- Javascript 的对象拷贝
- 程序员 30 岁前月薪达不到 30K,该何去何从
- 14 个最好的 JavaScript 数据可视化库
- 8 个给前端的顶级 VS Code 扩大插件
- Node.js 多线程齐全指南
- 把 HTML 转成 PDF 的 4 个计划及实现
- 更多文章 …