10 Bad Habits You Should Break When Writing Code in TypeScript

青灯夜游
Release: 2021-04-28 11:56:04
forward
1999 people have browsed it

10 Bad Habits You Should Break When Writing Code in TypeScript

TypeScript and JavaScript have been developing steadily in recent years. We've developed some habits in the past when writing code, and some of them don't make much sense. Here are 10 bad habits we should all break.

1. Not usingstrictmode

What does this habit look like

Not written in strict modetsconfig.json.

{ "compilerOptions": { "target": "ES2015", "module": "commonjs" } }
Copy after login

What should be done

Just enable thestrictmode:

{ "compilerOptions": { "target": "ES2015", "module": "commonjs", "strict": true } }
Copy after login

Why is this happening? Bad Habits

Introducing stricter rules into an existing code base takes time.

Why you shouldn’t do this

Stricter rules make it easier to maintain your code in the future, saving you a lot of time.

2. Define default values using||

What does this habit look like

Use the old||Default value for handling fallback:

function createBlogPost (text: string, author: string, date?: Date) { return { text: text, author: author, date: date || new Date() } }
Copy after login

What should I do

Use the new??operator, or redefine the default value in the parameter.

function createBlogPost (text: string, author: string, date: Date = new Date()) return { text: text, author: author, date: date } }
Copy after login

Why is there such a bad habit

??Operators were only introduced last year when using values in long functions , it can be difficult to set it as a parameter default.

Why you shouldn’t do this

??is different from||,??Only fornullorundefined, not applicable to all virtual values.

3. Feel free to useanytypes

What does this habit look like

When you are not sure about the structure, you can use theanytype.

async function loadProducts(): Promise { const response = await fetch('https://api.mysite.com/products') const products: any = await response.json() return products }
Copy after login

What should I do

Change any place in your code that usesanytounknown

async function loadProducts(): Promise { const response = await fetch('https://api.mysite.com/products') const products: unknown = await response.json() return products as Product[] }
Copy after login
Copy after login

Why is this a bad habit

anyis very convenient because it basically disables all type checking. Oftenanyis used even in officially provided types. For example, the TypeScript team set the type ofresponse.json()in the example above toPromise .

Why you shouldn't do this

It basically disables all type checking. Anything coming in viaanywill completely abandon all type checking. This will make errors difficult to catch.

4.val as SomeType

What does this habit look like

Forcibly tell the compiler a type that cannot be inferred.

async function loadProducts(): Promise { const response = await fetch('https://api.mysite.com/products') const products: unknown = await response.json() return products as Product[] }
Copy after login
Copy after login

How it should

This is whereType Guardcomes in.

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 { 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 }
Copy after login

Why is this a bad habit?

When switching from JavaScript to TypeScript, the existing code base often has types that the TypeScript compiler cannot automatically infer. Make assumptions. At this point, you can speed up the conversion byas SomeOtherTypewithout having to modify the settings intsconfig.

Why you shouldn't do this

Type Guardwill ensure that all checks are explicit.

5.as in the test

What does this habit look like

Create incomplete use cases when writing tests.

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) }
Copy after login

What should be done

If you need to mock test data, move the mocking logic next to the object you want to mock and make it reusable.

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) }
Copy after login

Why is this a bad habit?

When writing tests for code that does not yet have extensive test coverage, there are usually complex big data structures. But only some of them are needed for the specific functionality you want to test. Don't worry about other attributes in the short term.

Why not test.

6. Optional attributes

What does this habit look like

Mark attributes as optional properties, even if those properties sometimes do not exist.
interface Product { id: string type: 'digital' | 'physical' weightInKg?: number sizeInMb?: number }
Copy after login

How should

Clear which combinations exist and which do not.
interface Product { id: string type: 'digital' | 'physical' } interface DigitalProduct extends Product { type: 'digital' sizeInMb: number } interface PhysicalProduct extends Product { type: 'physical' weightInKg: number }
Copy after login

Why is this a bad habit?

It's easier and produces less code to mark a property as optional instead of splitting the type. It also requires a deeper understanding of the product being built, and may limit the use of code if the design of the product is modified.

Why you shouldn’t do this

The biggest benefit of the type system is that you can use compile-time checks instead of run-time checks. More explicit typing enables compile-time checks for errors that might go unnoticed, such as ensuring that everyDigitalProduct

has a

sizeInMb.

7. 用一个字母通行天下

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

用一个字母命名泛型

function head (arr: T[]): T | undefined { return arr[0] }
Copy after login

应该怎样

提供完整的描述性类型名称。

function head (arr: Element[]): Element | undefined { return arr[0] }
Copy after login

为什么会有这种坏习惯

这种写法最早来源于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' }
Copy after login

应该怎样

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

function createNewMessagesResponse (countOfNewMessages?: number) { if (countOfNewMessages !== undefined) { return `You have ${countOfNewMessages} new messages` } return 'Error: Could not retrieve number of new messages' }
Copy after login
Copy after login
Copy after login

为什么会有这种坏习惯

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

为什么不该这样做

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

9. ”棒棒“运算符

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

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

function createNewMessagesResponse (countOfNewMessages?: number) { if (!!countOfNewMessages) { return `You have ${countOfNewMessages} new messages` } return 'Error: Could not retrieve number of new messages' }
Copy after login

应该怎样

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

function createNewMessagesResponse (countOfNewMessages?: number) { if (countOfNewMessages !== undefined) { return `You have ${countOfNewMessages} new messages` } return 'Error: Could not retrieve number of new messages' }
Copy after login
Copy after login
Copy after login

为什么会有这种坏习惯

对某些人而言,理解!!就像是进入 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' }
Copy after login

应该怎样

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

function createNewMessagesResponse (countOfNewMessages?: number) { if (countOfNewMessages !== undefined) { return `You have ${countOfNewMessages} new messages` } return 'Error: Could not retrieve number of new messages' }
Copy after login
Copy after login
Copy after login

为什么会有这种坏习惯

如果你的代码在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

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

The above is the detailed content of 10 Bad Habits You Should Break When Writing Code in TypeScript. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:segmentfault.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!