Why is TypeScript a necessary language for developing large front-end projects

preface

How can I blame you for making a mistake? I gave you freedom too much. — Zhang Xinzhe, “Overreach”

Most software engineers probably know or understand TypeScript (TS for short) at some point, and front-end developers who have used TypeScript are surprisingly unanimous in their admiration of TypeScript. If you search for TypeScript in a search engine, you’ll find almost overwhelming articles that praise or praise TS, Examples include “TypeScript makes you want to go back to JavaScript”, “TypeScript Sniffing Series”, “If You Don’t Embrace TypeScript, You’re Old!”, and “If You Don’t Embrace TypeScript!”. . According to the latest State of JS Survey Report 2020, TypeScript’s Popularity and Satisfaction have increased year by year. More than 70% of developers are “TS fans” (” will continue to use “in State of JS), including this writer (see chart below).

In a word, TS now has an unshakable core position in the front-end field and is a very important front-end engineering development tool. TS is one of Microsoft’s outstanding contributions to the software industry after it embraced open source projects. However, TypeScript does not improve the efficiency of JavaScript code in the browser, nor does it improve developer productivity like the React and Vue front-end frameworks do, nor does it make your front-end pages look good and attractive. So what makes it such a popular “sweet language” and what makes it so appealing to front-end people? If you have such questions, read on for the rest of this article, which will explain in detail the advantages of using TS to develop large front-end projects.

TS introduction

TypeScript was born at Microsoft and was designed and developed by Anders Hejlsberg, chief architect of C# and founder of dotNet. TypeScript is simply JavaScript for the strongly typed system. It is a Superset of JS, that is, TS supports all syntax in JS, and it also extends many features of OOP. The first public version of TypeScript, 0.8, was released in October 2012 and was praised by Miguel de Ichaza, the father of GNOME, who pointed out that TypeScript’s biggest weakness was its lack of mature IDE support. For example, the only thing that supported TS at the time was Visual Studio running on Windows, so Mac and Linux users could not effectively use TS to write projects. However, this shortcoming was soon overcome. A year later, many editors, such as Eclipse, Sublime, Vim, and others, support TypeScript syntax. Today, TypeScript is effectively supported by most major editors. With TypeScript, you can easily use TS’s Autocomplete and Typing hints in the IDE to write reliable, high-quality code. As TypeScript explains on its official website: “Typed JavaScript at Any Scale”.

Interface oriented programming

TypeScript’s design concept comes from Interface-Oriented Programming (IOP), a programming pattern based on Abstract Type Constraint. To truly understand TypeScript, you first need to understand the concepts and principles of programming to interfaces. The paper “Interface Oriented Programming”, which initially introduced the concept of IOP, was published in 2004. It belongs to the object-oriented programming (OOP) system and is a more advanced and independent programming idea. As part of OOP architecture, IOP puts more emphasis on rules and constraints, as well as conventions for interface types and methods, allowing developers to focus on more abstract program logic as much as possible, rather than wasting time on more detailed implementation methods. Many large projects have adopted the IOP programming model.

The figure above is a schematic of the IOP programming pattern, which is common in OOP languages like Java or C#. The methods of a type are specified by the Interface, and the abstract methods defined in the Interface are implemented in the type. For example, IService interface defines Request(URL) and Auth(USR, PWD) methods, and this interface just defines the name, parameters and return value of the method regardless of how these two methods are implemented. The specific implementation is the core code to realize this function. This will be done in the Service class.

Such a design pattern that focuses on abstract method conventions has great advantages for building large projects. First, it does not require programmers to write any core code early in the program development or in the system design phase, so programmers can focus on the architectural design and business logic, and avoid wasting too much time thinking about the implementation. Secondly, because IOP has interfaces as an abstraction layer, it avoids exposing the core code details to developers. Developers who are not familiar with the module can quickly infer the program logic from documents, names, parameters, return values, etc., which greatly reduces the program complexity and maintenance costs. Finally, IOP can make programming more flexible, it naturally supports Polymorphic, and can be an effective substitute for Class Inheritance in OOP. While many beginners may complain that this design philosophy makes programming bloated, it’s fair to say that this additional constraint makes large projects more stable and vulnerable in the face of complexity and variability.

Readers may ask, what does this have to do with TypeScript? In fact, if you’ve ever written a large project in TS, you should be aware of the role that the concept of IOP plays in TS. Next, this article introduces some of the core concepts of TS, which will help you better understand what it is and why it is suitable for large projects.

TS Core Concepts

The basic grammar

As mentioned earlier, TS is a superset of JS, which means that the JS syntax TS includes all of it, and the type system is added on top of it.

:

:

:

Here are some examples of JavaScript and TypeScript code.

// JS
const strVal = 'string-value';
const objVal = {
  key: 'string-value',
  value: 1,
}
const func = param => param * 2;

And the analogous way of writing TS is like this.

// TS
const strVal: string = 'string-value';

interface IObject {
  key: string;
  value: number;
}
const objVal: IObject = {
  key: 'string-value',
  value: 1,
};

type Func = (param: number) => number;
const func: Func = (param: number) => param * 2;

See the difference? The first thing you might notice is that JS is much cleaner than TS. This is natural, because TS adds the type system, which inevitably adds some additional constraint code. JS is a weakly typed dynamic language, which can be converted freely between types, so it is very flexible. However, the coding euphoria generated by this flexibility and freedom can only last for a short period of time. As the project evolves, the types of variables increase, and the interactions between modules become more complex, the trouble caused by this freedom is likely to be catastrophic. This is what the rumour “dynamic is fun, reconstructing crematoria” suggests.

You may also notice that the object variable objVal is constrained by the interface IObject (it is defined using the interface keyword), which specifies the properties it requires and the corresponding types, so it cannot be assigned or evaluated arbitrarily. In the same way, functions can be defined with the keyword type, which defines the parameter name of the Function type Func, the type of the parameter, and the type of the result returned.

The base type

Like any major programming language, TypeScript has basic data types. Most of these are consistent with JavaScript’s basic data types, with the addition of some TS-specific types.

The list of basic types is as follows:

Type the name describe example
Boolean Boolean value const a: boolean = true;
Number The numerical const a: number = 1;
String string const a: string = 'text';
Array Array, indefinite length, same type const a: string[] = ['a', 'b'];
Tuple Tuples, fixed length, can be of different types const a: [string, number] = ['a', 1];
Enum The enumeration Website example
Unknown Not sure Website example
Any Any class Website example
Void No type Website example
Null and Undefined A null value Website example
Never For error-only functions, etc Website example
Object Object that represents a non-base type Website example

Interface and literal types

In addition to the base types, TS allows you to customize the types you need in your project. This custom Type is typically defined in TS by either an Interface or a Literal Type.

Interfaces are a very important core concept in TypeScript. Interface definition method is very simple, in TS code with interface keyword add interface name, followed by curly braces {… } and define the properties contained in this Interface and the corresponding types of the properties, which can be base types, interfaces, classes, and types. Note that a function is also a type. Here’s a code example.

interface Client { host: string; port? : string; username? : string; password? : string; connect: () => void; disconnect: () => void; } interface ResponseData { code: number; error? : string; message: string; data: any; } interface Service { name? : string; client: Client; request: (url: string) => ResponseData; }

Above is the interface definition code, let’s see how to use.

const client: Client = { host: 'localhost', connect: () => { console.log('connecting to remote server'); }, disconnect: () => { console.log('disconnecting from remote server'); }}; const service: Service = { name: 'Mock Service', client, request: (url: string) => { return { code: 200, message: 'success', data: url, }, }, };

This is a very simple code that simulates the client service definition. Note that the interface defines Attributes and Methods for Instance clients and services. Instances constrained by this interface must contain the required Attributes and correct types. Otherwise, an error will be returned at Compile Time. Interface with a question mark after the property name? Is the property is Optional. Therefore, the module or function is defined by the interface first, and the core logic in the interface is implemented after the general framework is considered, which satisfies the design pattern in interface-oriented programming.

Literal types, on the other hand, simplify some of the simpler custom types. Its definition is also very simple, limited by space will not expand on the explanation. Interested readers can go to the official website documentation for further information.

The duck type

Now that we know the basic types, interfaces, and literal types, we’re ready to start writing some solid code in TS. But in order to better understand the TS type system, we need to know when it is legal to bind an interface to an instance. How is type legality checked in TypeScript?

TypeScript employs a strategy known as “Duck Typing.” A duck type means that two types can be considered the same type when they have the same properties and methods. For example, dogs can eat and poop, and they have two eyes and one mouth; People can also eat and poop, and have two eyes and a mouth. By these attributes alone, dogs are the same type as humans. But that conclusion is clearly absurd. Humans can talk, but dogs can’t. Dogs can wag their tails, but humans can’t. But if an alien were to visit Earth, he or she would most likely classify dogs and humans as being able to eat, poop, and have two eyes and one mouth. But aliens can quickly categorize two organisms by looking at them selectively.

In fact, the duck type has some flexibility in addition to type constraints. The code is flexible and compact, not bloated by strict constraints. TypeScript validates types in this way, which improves the experience of writing TS and bypasses the rigid type constraints of traditional OOP languages such as Java and C#, making writing TS easy and fun.

other

Due to space constraints, this article will not elaborate on all TS features. However, there are many other useful features in TS, such as union types, enumerations, generics, namespaces, and so on. Readers who want to learn more about or use TS can go to the official documentation for more details.

Build large projects with TS

What is the first thing you associate with a large project? For development engineers in different fields, there may be different understandings. However, in the software industry alone, a software development Project is called a “Large Project”, which usually means a Large number of functional modules involved, thus having a high Complexity of the system. The success of a large project, in addition to meeting the traditional project management cycle, budget control, but also need to pay attention to quality, In terms of software engineering, this means Robustness, Stability, Maintainability, Scalability, and so on. Just like in construction, you don’t want to design a building that’s falling down. You want it to be as stable as possible, to stand up in the storm, and to be able to repair and maintain it flexibly. In order to ensure these non-functional requirements or quality requirements, there must be some clear specifications and standards, in the case of construction engineering may be engineering drawings, precision measurement, etc., In software engineering it’s Coding Standard, Design Patterns, Process Standard, System Architecture, Unit testing Testing) and so on. Code specifications and design patterns are particularly important because they are the foundation of the entire software system. Without code, there would be no software program. Without good code specifications and design patterns, there will be no good code and no reliable software programs, only a steady stream of program bugs and system crashes. TypeScript greatly improves code quality in terms of code specifications and design patterns, thereby enhancing system reliability, stability, and maintainability.

Code specification

Code style is often a pain point for front-end projects, and this can be regulated using the JavaScript style detector ESLint. However, ESLint can’t fix the type aspect. Only TypeScript can statically detect problems that may occur at the type level. If you were writing a front-end project in TS, I would recommend using type constraints for all possible variables and methods. And try not to use any, because any can cover all the other types, which is the same as having no type at all, which also loses the meaning of the type system.

Although TS has some extra type declaration code compared to pure JS, it is therefore more readable, understandable, and predictable, and therefore more stable and reliable. If you are a beginner switching from JS to TS, try to avoid using any as much as possible, as this will ruin your specifications and standards. If you have a back-end segregated architecture and are writing the front end in pure JS, without explicit and reliable back-end interface data structure conventions, you may be forced to write a lot of type-judging code, which pollutes the entire code style just like reflecting in a static language.

TS is just a static type system on top of JS. There is no other magic. But it’s this “small” addition that makes the code formal and maintainable, making it the first choice for large front-end projects. Many senior front-end engineers like to build large projects with React or Angular because they support TS. However, the recent release of Vue 3 adds TS support just in time to make it suitable for larger projects.

The directory structure

When writing large front-end projects, it is recommended that you use Declaration Files to manage interfaces or other custom types. The declaration file is usually in the form of

.d.ts, where only the types in the module are defined without any actual implementation logic. Declare files can be placed in a separate directory, which I like to call interfaces, which means interfaces. In this way, you can sufficiently separate abstract types, methods, properties, and so on from the actual content.

The following example is a VUE project directory with TS integrated.

.html - babel.config.js // babel.html - jest.config.ts // Unit Test Configuration Files - package.json // Project Configuration Files - public // Public Resource Bands SRC // source code directory │ ├─ app.vue // Main application │ ├─ Assets // Static Resources │ ├─ Components // Component - Constants // Constants │ ├─ I18N // Internationalization │ │ ├─ Anti-Flag ─ Interfaces // │ ├─ Anti-Flag ─ Index. D.ts // │ ├─ Anti-Flag ─ Layout // │ ├─ Anti-Flag ─ Store // │ ├─ Exercises - Main.ts // │ Exercises - Router // │ Exercises - Shims - Vue.ts // Comply with Vue Declaration file │ ├ ─ ─ store / / state management │ ├ ─ ─ styles / / CSS/SCSS style │ ├ ─ ─ the test / / test │ ├ ─ ─ utils / / public methods │ └ ─ ─ page views / / └ ─ ─ Tsconfig. json // TS configuration file

As you can see, the directory interfaces is at the same level as the other modules, and its subdirectories are the type declarations for the other modules. Before writing the code, try to create and design the content of the declaration file, and then go to the actual module to complete the implementation. Of course, this “define-> implementation” is an iterative process, and it is possible to find a type design problem during the implementation process, which can be refined back to the declaration file, and then optimized in the implementation code.

Design patterns

Before ES6, the JavaScript type system was difficult to understand, and one of the main reasons was its archetypal inheritance pattern, which was difficult to grasp. Before ES6, it was difficult to implement a factory approach in traditional OOP. However, ES6 has eased some of the front-end engineers’ pain points. ES6 introduces the class syntax sugar to implement traditional OOP class creation and inheritance. However, in TypeScript’s view, this is just a trivial matter. While the classes in ES6 give JS some encapsulation capabilities, they are not quite up to the task of building large projects or system modules. The lack of a type system, especially generics, is one of JS’s Achilles’ heel. Not only does TS have all the functionality of ES6 classes, but it also has interfaces, generics, decorators, and other features to implement a variety of flexible and powerful framework level systems. Generics are often a required feature of a framework class library to make a class or method more generic. I recommend extensive use of interfaces, generics, and other features in large projects to abstract your code and logic, to extract duplicate code, and to optimize the project as a whole.

How to Learn TS

The main purpose of this article is to encourage developers to build large front-end projects with TypeScript, rather than as a reference guide. Therefore, this article will not go into the details of how to create a TS project from scratch or how to write code using various TS features. Readers who are interested in further study of TS after reading this article need to read more TS reference articles for in-depth understanding.

For beginners, this article will give you some ways to quickly master TS.

The official documentation

Official documentation is the most authoritative reference guide, directly from the official documentation is the most systematic and the most effective way to learn.

  • Read the official TypeScript documentation carefully, including Get Started, Hand Book, Tutorials, and more.
  • If you’re not used to reading documentation in English, check out TypeScript Chinese for documentation.

Technical articles

TS has been developed for many years, and there are numerous technical articles about TS on the web. Here are just a few helpful blog posts.

  • TypeScript best practices
  • A rare TS study guide
  • Learn TypeScript by example
  • Maybe the React + TypeScript 50 specs and lessons you need

Practice project

“Truth comes out of practice”. In the process of learning, theory and practice are always inseparable. If you can apply what you have learned to a practical project, you will not only be impressed, but also experience the benefits and disadvantages of the new technology. You can try the following hands-on project approach.

  • Create a TypeScript project from scratch, using scaffolding tools such as Vue CLI, Create-React app, and build TS projects.
  • Learn about mature TS projects such as Ant Design, Nest, Angular, etc. Learn about how declaration files are organized.
  • Learn Open Source Project Definitelytyped and understand and practice how to get older JS projects to support TS.

conclusion

Embracing TypeScript is the mainstream of modern front-end engineering. Any front-end engineer needs to learn TS, which will help broaden your knowledge and skills as well as strengthen your expertise and professional background. However, we must realize that embracing TS is not the end. If you look at the history of the front-end, you’ll find that TypeScript’s popularity is the result of front-end engineering, modularity, and scaling, as the front-end requirements become more and more complex. TS is simply an effective solution to front-end engineering problems using back-end engineering knowledge. The creators of TypeScript revolutionized the productivity of front-end engineers by taking the lessons of C# and porting them to JavaScript. How long this solution will last is impossible to predict. But you can be sure that front-end engineering will continue to evolve and new technologies will emerge. As a software engineer, you need to keep learning so that you don’t get beaten to death on the beach.