共计 5919 个字符,预计需要花费 15 分钟才能阅读完成。
作者: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 === 的意思是字面意思是 ”。
点击关注,第一工夫理解华为云陈腐技术~