Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What syntax should TypeScript try to avoid?

2025-02-27 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)05/31 Report--

Today, I would like to share with you the relevant knowledge points of grammar that TypeScript should try to avoid. The content is detailed and the logic is clear. I believe most people still know too much about this knowledge, so share this article for your reference. I hope you can get something after reading this article.

Avoid enumeration

Enumeration provides a set of constants. In the following example, HttpMethod.Get is the name of the string 'Get'. The HttpMethod type is the same as a union type, such as' GET' | 'POST'.

Enum HttpMethod {Get = 'GET', Post =' POST',} const method: HttpMethod = HttpMethod.Post;method; / / Evaluates to 'POST'

Here are the reasons why enumerations are supported:

Suppose we end up replacing 'POST'' with 'post'. We can do this simply by replacing the value of the enumeration. The rest of our code does not need to be changed at all because it refers to HttpMethod.Post.

Now suppose that if we implement this scenario with a federation type. We defined the union types' GET' | 'POST', and then decided to change them to lowercase' get' | 'post'. Now if you use 'GET' or' POST' as the code for HttpMethod, you will report a type error. We need to change all the code manually. From this example, it is easier to use enumeration.

This example that supports the use of enumerations may not be so convincing. When we add an enumeration and union type, it is actually rarely changed after it is created. Using federated types does incur more change costs, but it's not really a problem, because it's actually rarely changed. Even if we have to change, because of the type error, we are not afraid to change less.

The disadvantages of using enumerations are:

We need to adapt to the syntax of TypeScript. TypeScript should be JavaScript, but static types have been added. If we remove the type of TypeScript, we should get a complete and valid JavaScript code. (translator's note: this reason is at the heart of the whole article, and one of the core benefits is that you can convert your ts code to js code through esbuild instead of tsc, a speed gap that can be 10-1000 times. And not introducing tsc means that there is one less area where something could go wrong. In the official documentation of TypeScript, the document that previously described TypeScript as a "type-level extension": that is, TypeScript is a type-level extension of JavaScript, and all TypeScript features do not change runtime behavior.

Here is an example of a type-level extension, an example of TypeScript:

Function add (x: number, y: number): number {return x + y;} add (1,2); / / Evaluates to 3

TypeScript's compiler checks the type of code. Then the code for JavaScript is generated. Fortunately, the process is simple: all the compiler has to do is remove the type tags. In this example, just take out: number, and here's the perfect JavaScript code:

Function add (x, y) {return x + y;} add (1,2); / / Evaluates to 3

Most TypeScript features have this feature and follow the law of type-level extension. To get the JavaScript code, you just need to get rid of the type standard.

However, enumerations break this rule. HttpMethod and HttpMethod.Post are part of the type. They should be removed. However, if the compiler removes this code, there will be a problem, because we are actually using HttpMethod.Post as a value type. If the compiler simply deletes the code, the code won't run away.

/ * This is compiled JavaScript code referencing a TypeScript enum. But if the * TypeScript compiler simply removes the enum, then there's nothing to * reference! * * This code fails at runtime: * Uncaught ReferenceError: HttpMethod is not defined * / const method = HttpMethod.Post

TypeScript's solution is to break its own rules. When compiling an enumeration, the compiler generates some JavaScript code itself. In fact, few TypeScript features do this, which actually complicates the compilation model of TypeScript. For these reasons, we recommend avoiding enumerations and replacing it with union types.

Why is the rule of type-level extension so important?

Let's see what happens when this rule interacts ecologically with the tool chains of JavaScript and TypeScript. TypeScript projects inherit from the JavaScript project, so it's normal to use packaging and compilation tools such as webpack and babel. These tools are designed for JavaScript, and even today, they are still focused on JavaScript. Every tool has its own ecology. There are countless ecological plug-ins that come with Babel and Webpack.

Is it possible for all Babel and Webpack and their ecological plug-ins to support TypeScript? For most TypeScript languages, in fact, the type extension rules make it easy for these content to support TypeScript. The tool just needs to get rid of the type standard and do the rest of the tools for the rest of the JavaScript.

When it comes to features like enumerations (including the namespace namespaces), this is a little more complicated. Enumerations cannot be simply removed. The tool needs to translate enum HttpMethod {...} into appropriate JavaScript code, because JavaScript does not have the enum keyword.

This will lead to some actual workload to deal with the problem of TypeScript breaking its own rules for type extension. People like Babel, webpack and their ecological plug-ins are all designed for JavaScript first, and TypeScript is generally just a feature they support. In many cases, TypeScript support does not receive the same support as JavaScript, there will be a lot of Bug. (translator's note: considering JavaScript actually makes these tools and plug-ins much less difficult, considering TypeScript, many problems actually become more complicated, and this increase in complexity is not necessarily valuable. To this day, the code and requirements of JavaScript are still much greater than TypeScript. Even for the purpose of reducing the complexity of these tools, these problems should not be introduced to solve TypeScript problems. The core runtime, still, and must be JavaScript. )

The work of many tools is mainly to deal with variable declarations and function declarations, which are relatively easy to do. But when it comes to enumerations and namespaces, you can't just remove type tags and start doing logic. You can certainly rely on TypeScript's compiler, but many less commonly used tools don't necessarily consider this issue.

When your compiler, Packer, compressor, linter, code formatter (actually code formatter is very easy to cause bug, especially for TypeScript) as long as there is a problem with the above, it is very difficult to debug. The compiler's Bug is very hard to find. When there is a bug, how many intuitively do you think it is the compiler's error? It is crucial that your code does not rely on the TypeScript compiler without using these features. ). The main text of this article: after a few weeks, with the help of my colleagues, we have a deeper understanding of this area of bug involvement. (note: I spent about two months studying TypeScript decorators and decorator metadata, and then planned to add them to my own framework. But in the end, I was frustrated to find that if I introduced them, I would not be able to use esbuild, because esbuild does not plan to support TypeScript's decorator metadata, but supports decorators, but this support is actually very new, and my entire framework is actually based on esbuild. I was frustrated and gave up TypeScript's decorator. (translator's note: it is unwise to introduce tsc because tsc is very complex. In fact, if you only use types, you basically get most of the tsc done during the code writing phase. As soon as you go to the type with esbuild at the end, you can continue. )

Avoid namespaces

Namespaces are similar to module, but there can be multiple namespaces in a file. For example, we introduce export code for different namespaces and their corresponding tests in a file. (we do not recommend the use of namespaces in this way, but here is just an example of discussion. )

Namespace Util {export function wordCount (s: string) {return s.split (/\ b\ w+\ bUnig) .length-1;}} namespace Tests {export function testWordCount () {if (Util.wordCount ('hello there')! = = 2) {throw new Error ("Expected word count for' hello there' to be 2");}} Tests.testWordCount ()

Namespaces can cause some problems in practice. In the example of the enumeration above, we saw TypeScript's law of type extension. Usually, TypeScript removes the type tagging, leaving behind the JavaScript code.

Namespaces naturally break this setting. In the namespace Util {export function wordCount...} code, we can't get the JavaScript code simply by removing the type tags. The entire namespace is a TypeScript type definition! Use Util.wordCount (...) in other code. What's going to happen? If we delete the Util namespace and then generate the JavaScript code, the Util is gone. So Util.wordCount (...) I can't work either.

Just like enumerations, TypeScript can't just delete namespace definitions, but generate some JavaScript code.

For enumerations, we recommend replacing them with union types. For namespaces, we suggest using ESM instead. Although it is troublesome to create a lot of files. But the two can achieve exactly the same effect.

Avoid decorators (for now)

A decorator is a method that can modify and replace other functions or classes. Here is an example of a decorator found in the official TypeScript documentation:

/ / This is the decorator.@sealedclass BugReport {type = "report"; title: string; constructor (t: string) {this.title = t;}}

The @ sealed decorator implies C# 's sealed decorator. This decorator prevents other classes from inheriting this class. We can implement a function of sealed, then accept a class and modify it so that it cannot inherit the class.

The decorator was first added in TypeScript, and then JavaScript (ECMAScript) began the standardization process. In January 2022, the decorator is still an ECMAScript proposal stage 2 proposal. Stage 2 represents the "draft" (drafting) stage. The decorator proposal seems to have been stuck in the committee: in fact, it reached stage 2 in February 2019.

We recommend avoiding decorators before stage 3. Stage 3 refers to the "candidate" phase, or the stage 4 "finished" phase.

It is possible that ECMAScript will never complete the decorator proposal. If the proposal is not completed, the decorator is in the same situation as enumerations and namespaces. Using decorators means breaking TypeScript's type extension rules, and using this feature, many packaging tools may be problematic. We don't know how much it will let the decorator through, but the benefits of the decorator are not that great, so we choose to wait.

Some open source libraries, such as the famous TypeORM, use decorators very heavily. We acknowledge that TypeORM cannot be used if we follow our advice. Of course, using TypeORM and decorators is sometimes a good choice, but you should understand the problems caused by doing so, you know, the current standardization process of decorator proposals may never be over. (translator's note: if you want to enjoy the benefits of esbuild, the depth of the decorator may be a problem. Of course, if your business can be self-contained in a framework written by decorators, it may not be a very big problem. However, if JS's decorator appears, there may be a problem with the existing decorator framework. )

Avoid the Private keyword

TypeScript has two ways to make a type property private. The old method is the private keyword, which is unique to TypeScript. There is also a new way: # somePrivateField, this is the JavaScript way. Here is an example:

Class MyClass {private field1: string; # field2: string;...}

We recommend the # somePrivateField field. But the two methods are basically the same. However, we recommend using more of JavaScript's features.

These are all the contents of this article entitled "what grammars TypeScript should try to avoid". Thank you for reading! I believe you will gain a lot after reading this article. The editor will update different knowledge for you every day. If you want to learn more knowledge, please pay attention to the industry information channel.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report