作者: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  }}

为什么会有这种坏习惯

?? 运算符是去年才引入的,当在长函数中应用值时,可能很难将其设置为参数默认值。

为什么不该这样做

??|| 不同,?? 仅针对 nullundefined,并不适用于所有虚值。

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'}

为什么会有这种坏习惯

编写简短的检测代码看起来更加简洁,使咱们可能防止思考理论想要检测的内容。

为什么不该这样做

兴许咱们应该考虑一下理论要查看的内容。例如下面的例子以不同的形式解决 countOfNewMessages0 的状况。

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 世界的入门典礼。它看起来简短而简洁,如果你对它曾经十分习惯了,就会晓得它的含意。这是将任意值转换为布尔值的便捷形式。尤其是在如果虚值之间没有明确的语义界线时,例如 nullundefined''

为什么不该这样做

与很多编码时的便捷形式一样,应用 !! 实际上是混同了代码的实在含意。这使得新开发人员很难了解代码,无论是对个别开发人员来说还是对 JavaScript 来说都是老手。也很容易引入轻微的谬误。在对“非布尔类型的值”进行布尔查看时 countOfNewMessages0 的问题在应用 !! 时依然会存在。

10. != null

这种习惯看起来是什么样的

棒棒运算符的小弟 ! = null使咱们能同时查看 nullundefined

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'}

为什么会有这种坏习惯

如果你的代码在 nullundefined 之间没有显著的区别,那么 != 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个计划及实现

  • 更多文章...