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. — Zhang Xinzhe, “Gone Too far”
Most software engineers probably know or understand TypeScript (TS) at some point, and front-end developers who have used TypeScript are surprisingly consistent in their love of TypeScript. If you search for TypeScript in a search engine, you’ll be bombarded with articles praising or praising TS, such as “TypeScript Makes you Want to Stop Using JavaScript”, “TypeScript Smells Good”, and “If you don’t embrace TypeScript, you’re Getting old! ” . According to the latest State of JS Report 2020, TypeScript’s Popularity and Satisfaction are increasing year by year. Even more than 70% of developers, including this author, are “TS fans” (who answered “will continue to use” in State of JS) (see chart below).
In a word, TS now plays an unshakable core role 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 embracing open source projects. TypeScript, however, doesn’t make JavaScript code run more efficiently in the browser, doesn’t make developers as productive as React and Vue front-end frameworks, and doesn’t make front-end pages as attractive as possible. So what is it about it that makes it such a popular “smell language”, and what is it about it that makes front-end people love it so much? If you have such a question, read on to explain in detail the advantages of developing large front-end projects with TS.
TS introduction
TypeScript was created at Microsoft by Anders Hejlsberg, chief architect of C# and founder of dotnet. TypeScript is simply JavaScript for a strongly typed system. It is a Superset of JS, that is, TS supports all the syntax in JS and extends many of the functions of object-oriented programming (OOP). TypeScript’s first public release, 0.8, was released in October 2012 and was praised by GNOME founder Miguel de Icaza, who pointed out that TypeScript’s biggest drawback was its lack of mature IDE support. For example, the only support for TS at the time was Visual Studio running on Windows, so Mac and Linux users could not write projects effectively with TS. However, this shortcoming was soon overcome. A year later, many editors, such as Eclipse, Sublime, Vim, and others, began supporting TypeScript syntax. Today, most major editors support TypeScript effectively. With TypeScript, you can enjoy TS’s Autocomplete and Typing hints in your IDE to write reliable and high-quality code. As the TypeScript website describes: “Typed JavaScript at Any Scale”.
Interface oriented programming
TypeScript’s design philosophy comes from interface oriented programming (IOP), a programming pattern based on Abstract Type constraints. To really understand TypeScript, you need to understand the concepts and principles of interface oriented programming. The paper “Interface Oriented Programming”, which first 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 the OOP architecture, IOP puts more emphasis on rules and constraints, as well as conventions for interface type methods, allowing developers to focus as much on more abstract program logic as possible, rather than wasting time on more detailed implementations. Many large projects use the IOP programming model.
The diagram above shows the IOP programming pattern, which is common in OOP languages such as Java or C#. Methods of a Class are contracted by an Interface, and abstract methods defined in an Implement Interface are required in a type. For example, IService interface defines Request(URL) and Auth(usr, PWD) methods. However, this interface only defines the method name, parameter and return value regardless of how these two methods are implemented. The specific implementation is the core code to achieve this function. This will be done in the Service class.
Such a design pattern, which focuses on abstract method conventions, has great advantages for building large projects. First, it does not require programmers to write any core code in the early stages of program development or system design, so that programmers can focus on architectural design and business logic and avoid wasting too much time thinking about concrete implementation. Secondly, due to the interface abstraction layer in IOP, the core code details are not exposed to developers. Developers who are not familiar with the module can quickly infer the program logic from documents, names, parameters, return values and so on, which greatly reduces the complexity of the program and maintenance costs. Finally, IOP can make programming more flexible with innate Polymorphic support as a valid alternative to Class Inheritance in OOP. While many beginners may complain that this design philosophy makes programming bloated, the added constraints make large projects more stable and vulnerable to complexity and variability.
Readers may ask, what does this have to do with TypeScript? In fact, if you’ve ever written a large project with TS, you can see how the concept of IOP can play a role in TS. Next, this article introduces some of the core concepts of TS, which will help the reader further understand the features of TS and why it is suitable for large projects.
TS Core Concepts
The basic grammar
As mentioned earlier, TS is a superset of JS, that is to say, JS syntax TS includes all, and on this basis also added a type system. A type is defined by adding a colon to the name of a variable or attribute and the type, that is,
:
. 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;
Copy the code
And the equivalent of TS is written 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;
Copy the code
See the difference? The first thing you might notice is that JS is much cleaner than TS. This is natural, because TS adds a type system, which inevitably adds some extra constraint code. JS is a weakly typed dynamic language, which can be converted freely between types and is very flexible. However, the coding pleasure generated by this flexibility and freedom only lasts for a short time, and the trouble caused by this freedom can be catastrophic as the project grows, variable types grow, and module interactions become more complex. This is what people say in the street: “The dynamic is good, the crematorium is rebuilt”.
You may also notice that the object variable objVal is constrained by the IObject interface (defined by the keyword interface), which specifies the required properties and corresponding types, and therefore cannot be arbitrarily assigned or evaluated. Similarly, functions can be defined with the keyword type, which defines the parameter name, parameter type, and result type of the Function type Func.
The base type
Like other major programming languages, TypeScript has basic data types. Most of these are consistent with JavaScript’s base data types, and some TS-specific types have been added.
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, variable 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 | Used for throwing error-only functions, etc | Website example |
Object | Object representing a non-base type | Website example |
Interfaces and literal types
In addition to the base types, you can also customize the types needed in a project. This custom Type is defined in TS by Interface or Literal Type.
Interfaces are an important core concept in TypeScript. Interface definition method is very simple, in the TS code with interface keyword and interface name, followed by curly braces {… }, and define the attributes contained in this Interface and the corresponding types of attributes in curly braces. The attributes can be basic types, interfaces, classes, and types. Note that functions are also types. The following are code examples.
interface Client {
host: string; port? :string; username? :string; password? :string;
connect: () = > void;
disconnect: () = > void;
}
interface ResponseData {
code: number; error? :string;
message: string;
data: any;
}
interfaceService { name? :string;
client: Client;
request: (url: string) = > ResponseData;
}
Copy the code
That’s the interface definition code. Let’s see how it works.
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,
},
},
};
Copy the code
This is a very simple code that emulates the client service definition. Note that the interface defines Attributes and Methods for the Instance client and service. Instances under this interface constraint must contain the required Attributes and the correct types. Otherwise, an error will be reported at Compile Time. Does the interface have a question mark after the attribute name? Is indicates that the attribute is Optional. Therefore, modules or functions are defined by the interface first, and then the core logic in the interface is realized after the big framework is considered, which satisfies the design pattern in interface oriented programming.
Literal types, on the other hand, tend to simplify relatively simple custom types. The way it is defined is also very simple, so I don’t have space to explain it. 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 can start writing some solid code in TS. But to further our understanding of TS type systems, we need to know when binding an interface to an instance is legal. How does TypeScript define type validity checks?
TypeScript uses a strategy called Duck Typing. Duck types are considered the same type when two types have the same properties and methods. For example, a dog can eat and poop, and has two eyes and one mouth. A man, too, can eat, poop, and have two eyes and one mouth. By these attributes alone, dogs and humans are of the same type. But this conclusion is clearly absurd. Humans can talk, but dogs can’t. A dog can wag its tail, but a man can’t. But if an alien were to visit Earth, he or she would probably put people and dogs in the same category, because they can eat, poop, and have two eyes and one mouth. But by selectively observing both species, aliens can quickly classify them.
In fact, duck type in type constraints at the same time, but also with some flexibility, the code appears flexible and concise, not because of strict constraints and let the code become bloated. TypeScript validates types in this way. It improves the experience of writing TS, bypassing the rigid type constraints of traditional OOP languages such as Java and C#, making writing TS easier and more fun.
other
Due to space reasons, this article does not attempt to cover all the features of TS. However, there are many other useful features in TS, such as union types, enumerations, generics, namespaces, etc. Readers who want to learn more about OR use TS should check out the official documentation.
Build large projects with TS
What is the first thing that comes to mind for large projects? For development engineers in different fields, there may be different interpretations. However, in the software industry alone, a software development Project is referred to as a “Large Project”, which usually means that a Large number of functional modules will be involved, resulting in higher Complexity. The success of a large-scale project, in addition to meeting the cycle and budget control of traditional project management, also needs to pay attention to quality. Robustness, Stability, Maintainability, Scalability, and so on from the perspective of software engineering. Like a building project, you don’t want your building to be rickety, you want it to be as strong as possible, to withstand heavy winds and storms, and to be flexible to repair and maintain. 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, engineering drawings, precision measurements, etc., In software engineering, it’s Coding standards, Design Patterns, Process Standards, System Architecture, Unit testing Testing) and so on. The 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 programs; Without good code specifications and design patterns, there would be no good code, no reliable software programs, just a steady stream of bugs and system crashes. TypeScript dramatically improves code quality through code specifications and design patterns, which in turn enhances system reliability, stability, and maintainability.
Code specification
Code style is often a pain point in front-end projects, and this can be regulated using the JavaScript style checker ESLint. ESLint, however, cannot solve the type problem. Only TypeScript can statically detect problems 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 don’t use any if possible, because any can cover all other types, which is equivalent to no type at all, which defeats the point of a type system.
Compared to pure JS, TS has some extra type declaration code, but it is more readable, understandable, and predictable, and therefore more stable and reliable. If you are a beginner switching from JS to TS, refrain from using any as much as possible; it will ruin your specifications and standards. If you have a forward-to-back architecture and are writing front ends in pure JS, you may be forced to write a lot of type-judging code without a clear and reliable convention for the data structure of the back-end interface, just as using Reflection in static languages taints the entire code style.
TS is simply a static type system on TOP of JS, no other magic. But it’s this “little” add-on that makes the code canonical and maintainable, making it the first choice for large front-end projects. Many advanced front-end engineers like to build large projects with React or Angular because they support TS. However, the recent release of Vue 3 also added TS support in time to make it suitable for large-scale projects.
The directory structure
When writing large front-end projects, it is recommended to use Declaration Files to manage interfaces or other custom types. Declaration files are usually in the form of
.d.ts, where only the types in the module are defined without any actual implementation logic. The declaration file can be placed in a separate directory, which I like to call interfaces, which stands for interfaces. In this way, you can sufficiently separate abstract types, methods, properties, and so on from the actual content.
The following example is a directory of Vue projects that integrate TS.
. ├ ─ ─ Babel. Config. Js / / Babel compiler configuration file ├ ─ ─ jest. Config. The ts / / unit test configuration file ├ ─ ─ package. The json / / project configuration file ├ ─ ─ public / / public resources ├ ─ ─ SRC // Source directory │ ├─ app.vue │ ├─ Assets │ ├─ Components │ ├─ Constants // Constants │ ├─ i18N // International │ ├ ─ ─ interfaces / / declaration file directory │ │ ├ ─ ─ the components / / component declare │ │ ├ ─ ─ the index, which s / / the main statement │ │ ├ ─ ─ layout / / layout statement │ │ ├ ─ ─ store / / │ ├─ ├─ bass Exercises, ├─ bass Exercises, exercises, exercises, exercises, exercises, exercises, exercises, exercises, exercises, exercises Declaration document │ ├─ State Management │ ├─ styles // CSS/SCSS style │ ├─test/ / test │ ├ ─ ─ utils / / public methods │ └ ─ ─ page views / / └ ─ ─ tsconfig. Json / / TS configuration fileCopy the code
As you can see, interfaces are at the same level as other modules, and their subdirectories are their type declarations. Before writing the code, as far as possible to create and design the declaration file content, after the design to the actual module to complete the implementation. Of course, this “define -> implement” is an iterative process. It is possible to find a type design problem during the implementation, which can be refined back to the declaration file, and then to the implementation code for optimization.
Design patterns
Before ES6 came out, JavaScript’s type system was somewhat difficult to understand, and one of the main reasons was its hard-to-grasp stereotype inheritance pattern. Before ES6, it was difficult to implement a traditional OOP factory approach. However, the ES6 has eased front-end engineers’ pain points. ES6 introduces class syntactic sugar to implement traditional OOP class creation and inheritance. However, in TypeScript, this is just “small noise”. While classes in ES6 give JS some of the ability to encapsulate, they are not as powerful when building large projects or system modules. The lack of a type system, especially generics, is the Achilles heel of JS. TS not only has all the functions of ES6 classes, but also interfaces, generics, decorators and other functions to achieve a variety of flexible and powerful frame-level systems. Generics are often a required feature of framework libraries to make a class or method more generic. I recommend extensive use of interfaces, generics, and other features in large projects to abstract away your code and logic in order to extract duplicate code and 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 in TypeScript, not as a guide. Therefore, this article will not go into the details of how to create A TS project from scratch, or how to code with the various TS features. Readers who are interested in further research on TS after reading this article should read more TS reference articles for further understanding.
For starters, this article will give you some ways to quickly master TS.
The official documentation
The official document is the most authoritative reference guide, directly from the official document is the most systematic and effective way to learn.
- Peruse TypeScript’s official documentation, including Get Started, Hand books, Tutorials, and so on.
- If you’re not used to reading Documents in English, check out TypeScript Chinese.
Technical articles
TS has been in development for many years, and there are plenty of technical articles about TS on the web. Here are some helpful blog posts.
- Typescript best practices
- A rare TS study guide
- Learn Typescript by example
- Probably the 50 React + TypeScript specs and experience you need
Practice project
“Truth comes from practice”. In the learning process, theory and practice are always inseparable. If I can apply what I have learned to practical projects, I will not only deepen my impression, but also personally experience the benefits and disadvantages of new technology. You can try the following ways to practice the project.
- Create a TypeScript project from scratch, using scaffolding tools like Vue CLI, create-React-app, etc.
- Learn about mature TS projects, such as Ant Design, Nest, Angular, etc., to understand how declaration files are organized.
- Learn DefinitelyTyped open source projects, understand and practice how to get old JS projects to support TS.
conclusion
Embracing TypeScript is a mainstay 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 career background. However, we must realize that embracing TS is not the end. If you’ve studied the history of the front end, you’ll see that TypeScript’s popularity is the result of the front end becoming engineered, modular, and scalable, a natural consequence of the increasing complexity of front-end requirements. TS is simply an effective solution to a front-end engineering problem with back-end engineering knowledge. The fathers of TypeScript cleverly ported the lessons of C# to JavaScript to create TypeScript, revolutionizing the productivity of front-end engineers. 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 pounded to death on the beach.