> 웹 프론트엔드 > JS 튜토리얼 > TypeScript로 코드를 작성할 때 버려야 할 10가지 나쁜 습관

TypeScript로 코드를 작성할 때 버려야 할 10가지 나쁜 습관

青灯夜游
풀어 주다: 2021-04-28 11:56:04
앞으로
2128명이 탐색했습니다.

TypeScript로 코드를 작성할 때 버려야 할 10가지 나쁜 습관

TypeScript와 JavaScript는 최근 몇 년간 꾸준히 발전해 왔습니다. 우리는 과거에 코드를 작성할 때 몇 가지 습관을 길러왔는데, 그 중 일부는 별로 의미가 없습니다. 우리 모두가 버려야 할 나쁜 습관 10가지를 소개합니다.

1. strict 모드를 사용하지 않음

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(&#39;https://api.mysite.com/products&#39;)
  const products: any = await response.json()
  return products
}
로그인 후 복사

应该怎样

把你代码中任何一个使用 any 的地方都改为 unknown

async function loadProducts(): Promise<Product[]> {
  const response = await fetch(&#39;https://api.mysite.com/products&#39;)
  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(&#39;https://api.mysite.com/products&#39;)
  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 === &#39;string&#39;
}

async function loadProducts(): Promise<Product[]> {
  const response = await fetch(&#39;https://api.mysite.com/products&#39;)
  const products: unknown = await response.json()
  if (!isArrayOfProducts(products)) {
    throw new TypeError(&#39;Received malformed products API response&#39;)
  }
  return products
}
로그인 후 복사

为什么会有这种坏习惯

从 JavaScript 转到 TypeScript 时,现有的代码库通常会对 TypeScript 编译器无法自动推断出的类型进行假设。在这时,通过 as SomeOtherType 可以加快转换速度,而不必修改 tsconfig 中的设置。

为什么不该这样做

Type Guard 会确保所有检查都是明确的。

5. 测试中的 as any

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

编写测试时创建不完整的用例。

interface User {
  id: string
  firstName: string
  lastName: string
  email: string
}

test(&#39;createEmailText returns text that greats the user by first name&#39;, () => {
  const user: User = {
    firstName: &#39;John&#39;
  } as any
  
  expect(createEmailText(user)).toContain(user.firstName)
}
로그인 후 복사

应该怎样

如果你需要模拟测试数据,请将模拟逻辑移到要模拟的对象旁边,并使其可重用。

interface User {
  id: string
  firstName: string
  lastName: string
  email: string
}

class MockUser implements User {
  id = &#39;id&#39;
  firstName = &#39;John&#39;
  lastName = &#39;Doe&#39;
  email = &#39;john@doe.com&#39;
}

test(&#39;createEmailText returns text that greats the user by first name&#39;, () => {
  const user = new MockUser()

  expect(createEmailText(user)).toContain(user.firstName)
}
로그인 후 복사

为什么会有这种坏习惯

在给尚不具备广泛测试覆盖条件的代码编写测试时,通常会存在复杂的大数据结构,但要测试的特定功能仅需要其中的一部分。短期内不必关心其他属性。

为什么不该这样做

在某些情况下,被测代码依赖于我们之前认为不重要的属性,然后需要更新针对该功能的所有测试。

6. 可选属性

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

将属性标记为可选属性,即便这些属性有时不存在。

interface Product {
  id: string
  type: &#39;digital&#39; | &#39;physical&#39;
  weightInKg?: number
  sizeInMb?: number
}
로그인 후 복사

应该怎样

明确哪些组合存在,哪些不存在。

interface Product {
  id: string
  type: &#39;digital&#39; | &#39;physical&#39;
}

interface DigitalProduct extends Product {
  type: &#39;digital&#39;
  sizeInMb: number
}

interface PhysicalProduct extends Product {
  type: &#39;physical&#39;
  weightInKg: number
}
로그인 후 복사

为什么会有这种坏习惯

将属性标记为可选而不是拆分类型更容易,并且产生的代码更少。它还需要对正在构建的产品有更深入的了解,并且如果对产品的设计有所修改,可能会限制代码的使用。

为什么不该这样做

类型系统的最大好处是可以用编译时检查代替运行时检查。通过更显式的类型,能够对可能不被注意的错误进行编译时检查,例如确保每个 DigitalProduct 都有一个 sizeInMb이 습관은 어떻게 생겼나요

strict 모드를 사용하지 않음 tsconfig.json. 🎜
function head<T> (arr: T[]): T | undefined {
  return arr[0]
}
로그인 후 복사
로그인 후 복사

🎜해야 할 일

🎜 엄격 모드를 활성화하세요: 🎜
function head<Element> (arr: Element[]): Element | undefined {
  return arr[0]
}
로그인 후 복사
로그인 후 복사

🎜이 나쁜 습관은 왜 있는 걸까요< /h4> 🎜기존 코드 베이스에 더 엄격한 규칙을 도입하려면 시간이 걸립니다. 🎜

🎜이렇게 하면 안 되는 이유

🎜규칙을 엄격하게 하면 나중에 코드를 더 쉽게 유지 관리할 수 있어 많은 시간을 절약할 수 있습니다. 🎜🎜🎜2. ||를 사용하여 기본값을 정의하세요

🎜이 습관은 어떻게 생겼나요

🎜이전 The를 사용하세요 ||는 fallback의 기본값을 처리합니다: 🎜
function createNewMessagesResponse (countOfNewMessages?: number) {
  if (countOfNewMessages) {
    return `You have ${countOfNewMessages} new messages`
  }
  return &#39;Error: Could not retrieve number of new messages&#39;
}
로그인 후 복사
로그인 후 복사

🎜어떻게 해야 하나요

🎜새 ?? 연산자를 사용하세요. 또는 매개변수에서 기본값을 재정의합니다. 🎜
function createNewMessagesResponse (countOfNewMessages?: number) {
  if (countOfNewMessages !== undefined) {
    return `You have ${countOfNewMessages} new messages`
  }
  return &#39;Error: Could not retrieve number of new messages&#39;
}
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

🎜이게 왜 나쁜 습관인가요?

🎜?? 연산자는 작년에야 소개되었는데 긴 함수에서 값을 사용할 때 매개변수 기본값으로 설정하기는 매우 어렵습니다. 🎜

🎜이렇게 하면 안되는 이유

🎜?? ||와 달리 ?? null 또는 undefine의 경우에만 모든 가상 값에 적용되지 않습니다. 🎜🎜🎜3. 어떤 유형이든 자유롭게 사용해 보세요

🎜이 습관의 모습

🎜 구조에서는 any 유형을 사용할 수 있습니다. 🎜
function createNewMessagesResponse (countOfNewMessages?: number) {
  if (!!countOfNewMessages) {
    return `You have ${countOfNewMessages} new messages`
  }
  return &#39;Error: Could not retrieve number of new messages&#39;
}
로그인 후 복사
로그인 후 복사

🎜해야 할 일

🎜코드에서 any를 사용하는 모든 위치를 unknown🎜
function createNewMessagesResponse (countOfNewMessages?: number) {
  if (countOfNewMessages !== undefined) {
    return `You have ${countOfNewMessages} new messages`
  }
  return &#39;Error: Could not retrieve number of new messages&#39;
}
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

🎜으로 변경하세요. 이것이 왜 나쁜 습관인가요?

🎜any는 기본적으로 모든 유형 검사를 비활성화하므로 매우 편리합니다. 공식적으로 제공되는 유형에서도 any가 사용되는 경우가 많습니다. 예를 들어 TypeScript 팀은 위 예에서 response.json() 유형을 Promise <any>로 설정했습니다. 🎜

🎜이 작업을 수행하면 안되는 이유

🎜기본적으로 모든 유형 검사가 비활성화됩니다. any를 통해 들어오는 모든 항목은 모든 유형 검사를 완전히 포기합니다. 이렇게 하면 오류를 잡기가 어려워집니다. 🎜🎜🎜4. val as SomeType

🎜이 습관은 어떻게 생겼나요

🎜 컴파일러에게 그렇게 할 수 없다고 강제로 알립니다. 추론의 종류. 🎜
function createNewMessagesResponse (countOfNewMessages?: number) {
  if (countOfNewMessages != null) {
    return `You have ${countOfNewMessages} new messages`
  }
  return &#39;Error: Could not retrieve number of new messages&#39;
}
로그인 후 복사
로그인 후 복사

🎜어떻게 해야 할까요

🎜여기서 Type Guard가 필요합니다. 🎜
function createNewMessagesResponse (countOfNewMessages?: number) {
  if (countOfNewMessages !== undefined) {
    return `You have ${countOfNewMessages} new messages`
  }
  return &#39;Error: Could not retrieve number of new messages&#39;
}
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

🎜이것이 왜 나쁜 습관인가요?

🎜JavaScript에서 TypeScript로 전환할 때 기존 코드 기반은 TypeScript 컴파일러가 자동으로 추론할 수 없는 유형에 대해 가정하는 경우가 많습니다. 이 경우 as SomeOtherTypetsconfig의 설정을 수정하지 않고도 변환 속도를 높일 수 있습니다. 🎜

🎜이 작업을 수행하면 안되는 이유

🎜Type Guard는 모든 검사가 명시적으로 이루어지도록 보장합니다. 🎜🎜🎜5. 테스트에서 무엇이든

🎜이 습관은 어떻게 생겼나요

🎜테스트를 작성할 때 불완전한 사용 사례 만들기 . 🎜rrreee

🎜해야 할 일

🎜모의 테스트 데이터가 필요한 경우 모의 로직을 모의하려는 객체 옆으로 이동하여 재사용 가능하게 만드세요. 🎜rrreee

🎜이것이 왜 나쁜 습관인가요?

🎜아직 광범위한 테스트 적용 범위가 없는 코드에 대한 테스트를 작성할 때 일반적으로 테스트해야 할 복잡한 빅 데이터 구조가 있습니다. 그 중 일부는 특정 기능에 필요합니다. 단기적으로는 다른 속성에 대해 걱정하지 마세요. 🎜

🎜이 작업을 수행하면 안 되는 이유

🎜경우에 따라 테스트 중인 코드는 이전에 중요하지 않다고 생각했던 속성에 따라 달라지며 해당 기능에 대한 모든 테스트는 업데이트되었습니다. 🎜🎜🎜6. 선택적 속성

🎜이 습관의 모습

🎜속성이 존재하지 않더라도 선택사항으로 표시하는 경우가 있습니다. 🎜rrreee

🎜해야 할 일

🎜어떤 조합이 존재하고 어떤 조합이 존재하지 않는지 명확하게 하세요. 🎜rrreee

🎜이것이 왜 나쁜 습관인가요?

🎜유형을 분할하는 대신 속성을 선택 사항으로 표시하는 것이 더 쉽고 코드 생성도 적습니다. 또한 제작 중인 제품에 대한 더 깊은 이해가 필요하며, 제품 디자인이 변경되면 코드 사용이 제한될 수 있습니다. 🎜

🎜이 작업을 수행하면 안되는 이유

🎜 유형 시스템의 가장 큰 이점은 런타임 검사 대신 컴파일 시간 검사를 사용할 수 있다는 것입니다. 보다 명시적인 유형을 지정하면 모든 DigitalProductsizeInMb가 있는지 확인하는 등 눈에 띄지 않을 수 있는 오류에 대한 컴파일 타임 검사가 가능해집니다. 🎜

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 =&#39;Daniel&#39;,而不是 const strName =&#39;Daniel&#39;。同样,一个字母的变量名通常会令人费解,因为不看声明就很难理解它们的含义。

8. 对非布尔类型的值进行布尔检查

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

通过直接将值传给 if 语句来检查是否定义了值。

function createNewMessagesResponse (countOfNewMessages?: number) {
  if (countOfNewMessages) {
    return `You have ${countOfNewMessages} new messages`
  }
  return &#39;Error: Could not retrieve number of new messages&#39;
}
로그인 후 복사
로그인 후 복사

应该怎样

明确检查我们所关心的状况。

function createNewMessagesResponse (countOfNewMessages?: number) {
  if (countOfNewMessages !== undefined) {
    return `You have ${countOfNewMessages} new messages`
  }
  return &#39;Error: Could not retrieve number of new messages&#39;
}
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

为什么会有这种坏习惯

编写简短的检测代码看起来更加简洁,使我们能够避免思考实际想要检测的内容。

为什么不该这样做

也许我们应该考虑一下实际要检查的内容。例如上面的例子以不同的方式处理 countOfNewMessages0 的情况。

9. ”棒棒“运算符

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

将非布尔值转换为布尔值。

function createNewMessagesResponse (countOfNewMessages?: number) {
  if (!!countOfNewMessages) {
    return `You have ${countOfNewMessages} new messages`
  }
  return &#39;Error: Could not retrieve number of new messages&#39;
}
로그인 후 복사
로그인 후 복사

应该怎样

明确检查我们所关心的状况。

function createNewMessagesResponse (countOfNewMessages?: number) {
  if (countOfNewMessages !== undefined) {
    return `You have ${countOfNewMessages} new messages`
  }
  return &#39;Error: Could not retrieve number of new messages&#39;
}
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

为什么会有这种坏习惯

对某些人而言,理解 !! 就像是进入 JavaScript 世界的入门仪式。它看起来简短而简洁,如果你对它已经非常习惯了,就会知道它的含义。这是将任意值转换为布尔值的便捷方式。尤其是在如果虚值之间没有明确的语义界限时,例如 nullundefined&#39;&#39;

为什么不该这样做

与很多编码时的便捷方式一样,使用 !! 实际上是混淆了代码的真实含义。这使得新开发人员很难理解代码,无论是对一般开发人员来说还是对 JavaScript 来说都是新手。也很容易引入细微的错误。在对“非布尔类型的值”进行布尔检查时 countOfNewMessages0 的问题在使用 !! 时仍然会存在。

10. != null

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

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

function createNewMessagesResponse (countOfNewMessages?: number) {
  if (countOfNewMessages != null) {
    return `You have ${countOfNewMessages} new messages`
  }
  return &#39;Error: Could not retrieve number of new messages&#39;
}
로그인 후 복사
로그인 후 복사

应该怎样

明确检查我们所关心的状况。

function createNewMessagesResponse (countOfNewMessages?: number) {
  if (countOfNewMessages !== undefined) {
    return `You have ${countOfNewMessages} new messages`
  }
  return &#39;Error: Could not retrieve number of new messages&#39;
}
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

为什么会有这种坏习惯

如果你的代码在 nullundefined 之间没有明显的区别,那么 != null 有助于简化对这两种可能性的检查。

为什么不该这样做

尽管 null 在 JavaScript早期很麻烦,但 TypeScript 处于 strict 模式时,它却可以成为这种语言中宝贵的工具。一种常见模式是将 null 值定义为不存在的事物,将 undefined 定义为未知的事物,例如 user.firstName === null 可能意味着用户实际上没有名字,而 user.firstName === undefined 只是意味着我们尚未询问该用户(而 user.firstName === 的意思是字面意思是 ''

原文:https://startup-cto.net/10-bad-typescript-habits-to-break-this-year/

作者:Daniel Bartholomae

译文地址:https://segmentfault.com/a/1190000039368534

更多编程相关知识,请访问:编程入门!!

위 내용은 TypeScript로 코드를 작성할 때 버려야 할 10가지 나쁜 습관의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:segmentfault.com
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿