Author: Han Nianqi

Welcome to reprint or share, reprint please indicate the author and source!

A link to the

  • Add one if it helps youstar, will continue to be updated:Making the address
  • [Is being perfected…] The original address
  • [Is being perfected…] PPT presentation (open on PC)
  • [PDF version available] Sample project and document download

Writing purpose

I just joined a new company recently. Every new employee in the department needs to share technology, so I take this opportunity to sort out my knowledge system.

About the title

The title was originally intended to be an introduction to Typescript advanced usage, but considering that there are a lot of posts about Typescript advanced usage, it’s written very well, so I’m not going to do the same thing here. So I changed the title to an in-depth understanding of Typescript’s advanced uses, focusing on understanding rather than using.

The body of the

Preface: The title here seems to be “advanced usage”, many students may be said to be discouraged. In fact, Typescript as a strongly typed programming language is characterized by its ability to express types, which many full-fledged back-end languages can’t match. That’s true, but PHP is the best language, so if you understand its type system, it will be helpful in your daily development. But the flexible typing system also prevents Typescript from becoming a purely static language, but isn’t it nice to have a code prompt for every line of code?

For a better reading experience, you are advised to read on a widescreen browser.

The outline

  • Basis of preparation
  • Description of the Typescript type system
    • Typescript types support defining “function definitions”
    • Typescript types support “conditional judgment”
    • Typescript types support “data structures”
    • Typescript types support “scope”
    • Typescript types support “recursion”
    • summary
  • Usage scenarios and values of advanced usage
    • What can be called “advanced usage”?
    • Illustrate advanced usage scenarios
    • summary
  • Type derivation and generic operators
    • Flowing types (type writing ideas)
    • Typescript code philosophy
  • Common type derivation implements logical sorting
    • Type passing (flow)
    • Type of filtering and streaming
    • summary
  • 【 To be continued 】 Common generic operators to implement logic and practical introduction
  • Customize extensions to Typescript
    • Typescript Service Plugins background, function positioning, basic use
    • Examples of existing Typescript Service Plugins
    • 【 To be continued 】 How do I write Typescript Service Plugins myself
    • Resources link
  • Q&A (welcome to comment section)
    • Can the Typescript Service Plugin (for example, configuring ESLint rules) be used to block compilations or generate compile-time alarms?

Basis of preparation

Basic knowledge required to read this article.

Preliminary knowledge

The purpose of this paper is to understand advanced usage, so it will not involve too much explanation of basic knowledge. Readers are required to improve their knowledge reserves in this aspect.

By default, the content of this document requires the reader to have the following knowledge:
  1. There areJavascriptOr programming experience in other languages.
  2. There areTypescriptPractical experience, preferably complete use in a serious project.
  3. To understandTypescriptBasic syntax and the use of common keywords.
  4. rightTypescriptThe type systemThere is a basic understanding of architecture.

Related Resources recommendation

  1. The Typescript’s official website
  2. TypeScript Deep Dive
  3. The TypeScript making address

background

For those of you who are new to Typescript development, this is a problem:

  1. Code hints are not intelligent, and they seem to have to be explicitly typed to have code hints. It’s hard to understand how many people are following such a programming language.
  2. A variety of types of error reported suffering, thought to listen to online saidTypescriptYou can improve the maintainability of your code, only to find that you add a lot of development overhead.
  3. Defining all types explicitly seems to work for most of the common ones, but in some complex cases you find yourself unable to do anything but write down a fewas anyWaiting for codereviewPublic execution.
  4. The project is urgent and the time is tightTypescriptBecame the first problem, pondering for a moment to decide to take refugeAnyscriptQuickly develop business logic and come back to replenish types in the spring. Double the workload, double the happiness only oneself can understand.

In order to avoid the occurrence or recurrence of the above tragedy, only after we have a deeper understanding of it, can we play a better game in the development, in the development of the game.

Description of the Typescript type system

Question to consider: Some people say Typescript = Type + Javascript. Is Type a fully fledged programming language, regardless of Javascript?

Typescript types support defining “function definitions”

Students who have programming experience all know that function is one of the most basic functions in a programming language. Function is the basic unit of program encapsulation in procedural, object-oriented and functional programming, and its importance is self-evident.

Functions can help us do many things, such as:

  • Function can encapsulate the program into a function, and form the function internal variable scope, through static variables to preserve the function state, through the return value to return the result.
  • Functions can help us realize the reuse of procedures. If a piece of logic can be used more than once, it is encapsulated as a function, which can be called many times by other procedures.
  • Functions can also help us organize our code better and help us maintain our code better.
So, how do you define functions in the Typescript type system?

Functions in Typescript’s type system are called generic operators, and a simple way to define them is by using the type keyword:

// Here we define the simplest generic operator
type foo<T> = T;
Copy the code

How to understand the code here, in fact, here I convert the code into the most familiar Javascript code is actually not difficult to understand:

// Convert the type code above to 'JavaScript' code
function foo(T) {
	return T
}
Copy the code

So see here there are students in the mind to be suspicious, the heart you this is not fooling me? Isn’t that how Typescript defines types? The Type keyword is the same as the interface keyword. The Type keyword is the same as the interface keyword.

Well, you’re absolutely right, but don’t worry. In fact, functions in the type system also support constraints on input parameters.

// here we apply a type constraint to the input parameter T
type foo<T extends string> = T;
Copy the code

So what does it look like to convert this code to Typescript?

function foo(T: string) {
	return T
}
Copy the code

Of course, we can also set it to default:

// Here we add a default value to the input parameter T
type foo<T extends string = 'hello world'> = T;
Copy the code

So this code converts to Typescript like this:

function foo(T: string = 'hello world') {
	return T
}
Copy the code

Is it possible to support residual arguments like functions in JS?

Unfortunately, it is not currently supported, but there must be such a requirement in our daily development. Is there really nothing that can be done? In fact, not necessarily, we can simulate this kind of scene through a few SAO operation, of course, this is after the words, here is not extended.

Typescript types support “conditional judgment”

Life is full of choices, and programming is no different.

— I made it up

Conditional judgment is also one of the most basic functions in the programming language, and it is also the most commonly used function in our daily code process, whether it is if else or ternary operators, I believe we have used it.

So how do you implement type determination in the Typescript type system?

In fact, this is called Conditional Types in Typescript official documentation and is defined simply by using the extends keyword.

T extends U ? X : Y;
Copy the code

Here believe smart you can see at a glance, this is not the ternary operator! Yes, and it’s also very similar to the ternary operator, which returns X if T extends U is true and Y otherwise.

In combination with the “function” just described, we can simply extend it:

type num = 1;
type str = 'hello world';

type IsNumber<N> = N extends number ? 'yes, is a number' : 'no, not a number';

type result1 = IsNumber<num>; // "yes, is a number"
type result2 = IsNumber<str>; // "no, not a number"
Copy the code

Here we have implemented a simple function with judgment logic.

Typescript types support “data structures”

Simulating a real array

For example, the most common data types in Typescript are arrays or tuples.

Do you know how to do push, pop, shift, unshift on tuple types?

All of these operations can be implemented:

// Define a utility type to simplify the code
type ReplaceValByOwnKey<T, S extends any> = { [P in keyof T]: S[P] };

// shift action
type ShiftAction<T extends any[] > = ((. args: T) = > any) extends ((arg1: any. rest: infer R) = > any)? R :never;

// unshift action
type UnshiftAction<T extends any[], A> = ((args1: A, ... rest: T) = > any) extends ((. args: infer R) = > any)? R :never;

// pop action
type PopAction<T extends any[]> = ReplaceValByOwnKey<ShiftAction<T>, T>;

// push action
type PushAction<T extends any[], E> = ReplaceValByOwnKey<UnshiftAction<T, any>, T & { [k: string]: E }>;

// test ...
type tuple = ['vue'.'react'.'angular'];

type resultWithShiftAction = ShiftAction<tuple>; // ["react", "angular"]
type resultWithUnshiftAction = UnshiftAction<tuple, 'jquery'>; // ["jquery", "vue", "react", "angular"]
type resultWithPopAction = PopAction<tuple>; // ["vue", "react"]
type resultWithPushAction = PushAction<tuple, 'jquery'>; // ["vue", "react", "angular", "jquery"]
Copy the code

Note: this code is only for testing purposes, operating on some complex types may cause errors, need to do further compatibility processing, this simplifies the relevant code, do not use in production environment!

Most of you can already see the power of the Typescript type system. In fact, we will continue to improve the Typescript type system by adding common functions such as concat, map, and other arrays to tuples.

However, the “data types” mentioned above are not the “data types” I want to explain here. The above data types are essentially data types that serve the code logic, not the data types that serve the type system itself.

How to understand the above sentence?

In the same way that arrays and tuples are used to batch manipulate data in a broad sense, data structures that serve the type system itself should also be able to batch manipulate types.

So how do you batch operate on types? Or what is an array serving a type system?

This brings us to the real “arrays” of this section: Union Types

Speaking of Union Types, those of you who have used Typescript love/hate it:

  1. When defining a function entry parameter, use this function when multiple parameter types are allowed to be passed in the same positionUnion TypesCan be very convenient, but trying to intelligently deduce the type of return value is difficult.
  2. When the number of input arguments is uncertain, and do not want to write(... args: any[]) => voidThe egg – free parameter type definition.
  3. useUnion TypesAlthough there areType GuardBut it still doesn’t work well in some scenarios.

In fact, when you know enough about it, you’ll see that Union Types are much more useful than Intersection Types.

“Arrays” in the type system

Let’s take a closer look at Union Types:
How do I iterate over Union Types?

Since the goal is to batch manipulate types, type traversal is necessary, as is the in keyword in the Typescript type system, as is the case in most programming languages.

type key = 'vue' | 'react';

type MappedType = { [k in key]: string } // { vue: string; react: string; }
Copy the code

You see, with the in keyword, we can easily iterate over Union Types and make some changes to the Types.

But sometimes not all Union Types are explicitly defined.

What are the ways we want to dynamically derive Union Types?

You can use the keyof keyword to dynamically retrieve a keyof a key-value pair type

interface Student {
  name: string;
  age: number;
}

type studentKey = keyof Student; // "name" | "age"
Copy the code

Similarly, there are ways to retrieve tuple type subtypes

type framework = ['vue'.'react'.'angular'];

type frameworkVal1 = framework[number]; // "vue" | "react" | "angular"
type frameworkVal2 = framework[any]; // "vue" | "react" | "angular"
Copy the code

Practical application

If I want to batch map a set of Union Types to another type, how do I do that?

In fact, there are a lot of methods, here to provide a way of thinking, and other methods for students to study it.

In fact, the above requirements, it is not difficult to see that the requirements are somewhat similar to the array map method

So how do you implement a map function that operates on Union Types?
// Placeholder can be any type you want to map to
type UnionTypesMap<T> = T extends any ? 'placeholder' : never;
Copy the code

In fact, the smart students here can see that we only use Conditional Types so that the judgment condition is always true, so that it always returns the type on the left, and we can take the input parameter of the generic operator and customize our operation.

Let’s strike while the iron is hot: map each entry of a Union type to the return value of a function.

type UnionTypesMap2Func<T> = T extends any ? () = > T : never;

type myUnionTypes = "vue" | "react" | "angular";

type myUnionTypes2FuncResult = UnionTypesMap2Func<myUnionTypes>;
// (() => "vue") | (() => "react") | (() => "angular")
Copy the code

I believe that with the learning of the above content, we have had a relatively comprehensive understanding of Union Types. Based on this, we will make some advanced expansions in the future, which are as simple as chopping melons and vegetables.

Other data types

Of course, there are other data types besides arrays. For example, you can use type or interface to simulate literal objects in Javascript. One of the features is that you can retrieve subtypes using myType[‘propKey’]. Here is a primer, interested students can study by themselves.

Typescript types support “scope”

Global scope

Global scopes are supported in Typescript’s type system, as are common programming languages. In other words, you can get it anywhere in any file and use it without importing it.

Typically, use the DECLARE keyword, such as our common image resource type definition:

declare module '*.png';
declare module '*.svg';
declare module '*.jpg';
Copy the code

We can also declare a type in the global scope:

declare type str = string;
declare interface Foo {
  propA: string;
  propB: number;
}
Copy the code

Note that this declaration may not work if your module uses the export keyword. If you still want to declare the type globally, you need to declare the type globally explicitly:

declare global {
  const ModuleGlobalFoo: string;
}
Copy the code

Module scope

Just like modules in NodeJS, each file is a module, and each module is its own module scope. One of the conditions triggered by the module scope here is to export the content using the export keyword.

The content defined in each module is not directly available in other modules, but can be imported on demand using the import keyword if necessary.

Generic operator scope & function scope

Generic operators are scoped. Remember from the first section of this chapter I likened generic operators to functions for your understanding? Since functions can be analogous to functions, generic operators can also have the same properties, so it is easy to understand that there is a generic operator scope.

The two T’s defined here with the same name do not affect each other:

type TypeOperator<T> = T;
type TypeOperator2<T> = T;
Copy the code

That’s the description of the scope of the generic operator, but let’s talk about the real scope of the function:

Types can also support closures:

function Foo<T> () {
  return function(param: T) {
    returnparam; }}const myFooStr = Foo<string> ();// const myFooStr: (param: string) => string
// The closure is triggered and the type can still be preserved
const myFooNum = Foo<number> ();// const myFooNum: (param: number) => number
// Closures are triggered here, and the types remain independent of each other
Copy the code

Typescript types support “recursion”

Typescript types also support recursion. The problems associated with recursion are abstract, so here are some examples. I’ll also use Javascript syntax to describe type recursion as I did in the first section.

First let’s take an example:

Suppose you now want to extract the subtypes of a tuple type of any length, concatenate them and return them.

There are a lot of ways to solve this problem, and there are a lot of ways to solve this problem. Because this section is about recursion, we’re going to use recursion to solve this problem. No nonsense, first on the code:

// shift action
type ShiftAction<T extends any[] > = ((. args: T) = > any) extends ((arg1: any. rest: infer R) = > any)? R :never;

type combineTupleTypeWithTecursion<T extends any[], E = {}> = {
  1: E,
  0: combineTupleTypeWithTecursion<ShiftAction<T>, E & T[0]>
}[T extends[]?1 : 0]

type test = [{ a: string }, { b: number }];
type testResult = combineTupleTypeWithTecursion<test>; // { a: string; } & { b: number; }
Copy the code

Are you stunned to see the code above? That’s ok, let’s translate the above code using regular Typescript code.

function combineTupleTypeWithTecursion(T: object[], E: object = {}) :object {
  return T.length ? combineTupleTypeWithTecursion(T.slice(1), {... E, ... T[0] }) : E
}

const testData = [{ a: 'hello world' }, { b: 100 }];
{a: 'hello world', b: 100}
combineTupleTypeWithTecursion(testData);
Copy the code

Now, if you’re smart enough to see this, the recursion of the original type is essentially the same as the recursion of ordinary functions. If the end condition is triggered, it returns directly, otherwise the call continues recursively, passing the second argument to hold the result of the last recursive calculation.

Of course, those of you who are familiar with recursion know that in common programming languages, recursion is a very resource-intensive behavior, and once the maximum limit is exceeded the program will crash. The same is true for recursion in a type. If you recurse too deeply, the type system will also break down, so this code should be understood and should not be used in production.

summary

Remember that quiz question from the beginning? In fact, we can confidently say that Typescript Type is a full-fledged programming language in its own right, even a full-fledged Turing language. So types themselves can be used for programming, and you can use them to write interesting things, not to mention simple business scenarios that you encounter in everyday development.

Usage scenarios and values of advanced usage

What can be called “advanced usage”?

In fact, the so-called “advanced usage” is nothing more than a specific convention for solving certain situations known as writing or grammar sugar. Does advanced usage matter? Important and unimportant. According to the “80/20 rule” in programming, 20% of knowledge can already solve 80% of the requirements, but the remaining 20% is the dividing line between beginner and proficient.

In fact, as long as we carefully read the handbook provided by the official, we can already cope with the daily development. But as stated at the beginning of this article, do you think:

  1. TypescriptIn some cases it’s a lot harder to use than it isJavascriptOne tenth of the flexibility.
  2. Are you using it for yourselfJavascriptIn a certainSAO operationGloating about solving complex code in a very short piece of code is not correctThe return typeScratch your bald head.
  3. Did you knowingly use a number ofas xxxIt makes your code look bad, but you can’t do anything about it.

Student: When you solve these problems in some way, then it’s called advanced usage.

Illustrate advanced usage scenarios

Here’s an example: In the story has a function called combineReducers, because in some scenarios, we need to add a combineReducersParamFactory function, the function support to multiple functions, The return value of the passed function is used as the input parameter of the combineReducers function. We need to integrate the return value of multiple input parameter functions and generate the final object for use by the combineReducers function.

Think about the logic and realize that it’s not complicated and can be implemented easily with Javascript:

/** * merges the return values of multiple arguments and returns *@param { Function[] } reducerCreators
 * @returns { Object }* /
function combineReducersParamFactory(. reducerCreators) {
  return reducerCreators.reduce((acc, creator) = >({... acc, ... creator() }), {}) }// test ...

function todosReducer(state = [], action) {
  switch (action.type) {
    case 'ADD_TODO':
      return state.concat([action.text])
    default:
      return state
  }
}

function counterReducer(state = 0, action) {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1
    case 'DECREMENT':
      return state - 1
    default:
      return state
  }
}

const ret = combineReducersParamFactory(
  () = > ({ todosReducer }),
  () = > ({ counterReducer })
);
// { todosReducer: [Function: todosReducer], counterReducer: [Function: counterReducer] }
Copy the code

But how do you write it if you need a corresponding type?

type Combine<T> = (T extends any ? (args: T) = > any : never) extends (args: infer A) => any ? A : never;

/** * merges the return values of multiple arguments and returns *@param { Function[] } reducerCreators
 * @returns { Object }* /
function combineReducersParamFactory<T extends ((... args) =>object) [] > (. reducerCreators: T) :Combine<ReturnType<T[number] > >{
  return reducerCreators.reduce<any> ((acc, creator) = >({... acc, ... creator() }), {}); }// test ...

function todosReducer(state: object[], action: { [x: string] :string}) {
  switch (action.type) {
    case 'ADD_TODO':
      return state.concat([action.text])
    default:
      return state
  }
}

function counterReducer(state: number, action: { [x: string] :string}) {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1
    case 'DECREMENT':
      return state - 1
    default:
      return state
  }
}

// There is no need to display the incoming type, here is the correct code prompt
const ret = combineReducersParamFactory(
  () = > ({ todosReducer }),
  () = > ({ counterReducer })
);
// { todosReducer: [Function: todosReducer], counterReducer: [Function: counterReducer] }
Copy the code

You see, types are carefully choreographed so that callers can enjoy the joy of code hints without any additional burden.

summary

After this chapter, it became clear that our carefully choreographed types could become very intelligent, allowing callers to enjoy the joy of code hints at almost no cost. It may cost a lot of time to arrange the type, but once we complete the arrangement, we can greatly reduce the mental burden of the caller, so that the caller can enjoy the joy of programming.

Type derivation and generic operators

Flowing types (type writing ideas)

Those familiar with functional programming must have a deep understanding of the concept of data flow. When you change a value in the “upstream”, the “downstream” will automatically update. For those of you who have experience in responsive programming, this is the time to put up your hands. Put your hands down. We don’t want to get into the idea of streaming here, but we want to draw on these concepts by analogy to the main point of this section: types of flows.

Yes, the idea of writing a type system can be borrowed from functional programming. So when one type changes, other related types are automatically updated, and you get a friendly reminder when the code is too bloated to maintain, as if the whole type system were a carefully designed constraint system.

Typescript code philosophy

Now that we’ve talked about type systems, let’s talk about code philosophy. One of the biggest reasons Typescript is becoming so popular right now is that, aside from the overstated advantages of Typescript, it’s powerful type representation and its editor (VSCode) is full of code hints.

On the basis of these advantages, I have developed some coding philosophies (habits).

  1. Reduce unnecessary explicit type definitions, use type derivation as much as possible, and let the flow of types be as natural as breathing.
  2. Use as little as possibleanyas anyNote that this does not mean that it cannot be used, but that you can use it in the current situationanyIs the optimal solution.
  3. If you want to useanyAs a type, consider whether it can be used firstunknownType substitution, after allanyBreaks the flow of types.
  4. Use as little as possibleas xxxIf you use a lot of this way to correct types, then chances are you’re rightTypes of flowI don’t understand it very well.

Common type derivation to achieve logical sorting and practical introduction

Type passing (flow)

As we said earlier, types are fluid, and it’s easy to understand with the concept of responsive programming. In this section, we will illustrate some common examples.

Those of you with programming experience know that data can be passed, and so can types.

You can use type to create a pointer to the corresponding type, and then you can pass the type. You can also specify an alias, or a copy.

type RawType = { a: string.b: number };

// Here is the reference of the above type
type InferType = RawType; // { a: string, b: number };
Copy the code

Similarly, types can be passed as data is passed:

var num: number = 100;
var num2  = num;

type Num2Type = typeof num2; // number
Copy the code

This is what makes Typescript capable of type checking, defining jumps, and so on.

Hands up if you’re familiar with streaming programming at this point: you’re talking about type passing, input and output, but what if I want to manipulate it while it’s passing? Don’t worry, this is what I want to say next.

Type of filtering and streaming

In the last section, we talked about functional programming, reactive programming, and streaming programming over and over again. This is not a digression, but the concepts are so similar that I will continue to use these concepts for the rest of this section. Take a look at some of the most popular functional programming libraries, whether Ramda, RXJS, or the familiar lodash and underscore, and there must be an operator called filter, or underscore, for filtering data streams.

This operator must be used far more often than any other operator, so how do we implement such an important function in the type system?

To solve this problem, here is a question that is very frequently searched in the tech community/platform:

What exactly does the never type in TypeScript do?

Since this question is so frequently searched, I won’t repeat it here. For those who are interested, take a look at the answer: What exactly is the use of the never type in TypeScript? – Yuxi’s answer – Zhihu.

Here’s a brief summary:

  1. neverRepresents an empty set.
  2. This is often used to verify that “type narrowing” is expected, that is, writing type safe code.
  3. neverIt is often used as a “type pocket”.

Of course, the summary above is not complete, but it is enough to help you understand the content of this section. If you are interested, please refer to the relevant materials.

The “type narrowing” mentioned above is pretty close to our goal, but of course we also need to understand the performance of never participating in type operations:

type NeverTest = string | never // stirng
type NeverTest2 = string & never // never
Copy the code

Important knowledge emerged: T | never, the results for T.

We can use never to filter out undesirable Union Types. This generic operator has been documented in Typescript 2.8.

/** * Exclude from T those types that are assignable to U */
type Exclude<T, U> = T extends U ? never : T;
Copy the code

I believe that after such a long time of learning, see here you must be very easy to write this way of thinking.

Ok, so with filtering out of the way, let’s talk about shunting. The concept of type triage is not difficult to understand. It is often associated with logical judgments. After all, from a logical level, Union Types are essentially used to describe the relationship between or. This same concept, when introduced to streaming programming, naturally leads to streaming. In plain English, different data should be sorted and sent to different pipes, and so should types.

So how do you handle common features in Typescript? In fact, this common problem is also taken into consideration by the official very kindly, that is: Type guard. There are many articles explaining Type Guard on the Internet, which will not be described here. Students who are interested in Type Guard can search and learn by themselves. Let’s use a simple chestnut to briefly demonstrate usage:

function foo(x: A | B) {
  if (x instanceof A) {
    // x is A
  } else {
		// x is B}}Copy the code

Common ways that type guards can be triggered are typeof, instanceof, in, ==, ===,! =,! = =, and so on.

Of course, in some scenarios, the above methods alone cannot meet our needs. What should we do? In fact, the official has already helped me to consider this problem: using the IS keyword to customize Type guard.

// Note that the Boolean type needs to be returned
function isA(x) :x is A {
  return true;
}

// Note that the Boolean type needs to be returned
function isB(x) :x is B {
  return x instanceof B;
}

function foo2(x: unknown) {
  if (isA(x)) {
    // x is A
  } else {
    // x is B}}Copy the code

summary

In this chapter, we use the analogy of reactive programming and streaming programming to help you better understand the implementation logic and thinking of Typescript type inference. We believe that after learning this chapter, we have a deeper understanding of Typescript type inference. However, this chapter introduces a lot of abstract concepts, and it is also a bit complicated. If you are not very good at basics, you need to spend more time looking through relevant materials.

【 To be continued 】 Common generic operators to implement logic and practical introduction

Customize extensions to Typescript

Typescript Service Plugins background, function positioning, basic use

background

Whether you use ts-loader or babel-loader in webpack or gulp-typescript in gulp, you are familiar with Typescript compilation methods. Or use Typescript’s built-in command-line tools. Most of you are already familiar with Typescript.

Here we focus on the Typescritp experience. Some of the most common problems encountered in Typescritp front-end development are:

  1. When dealing with type definitions for style resources in CSS Modules, you are not satisfied with usingdeclare module '*.module.css'This type definition has no use for eggs.
  2. Not wanting to install all kinds of plugins to the editor, the next time you start the editor will take significantly longer, the small computer will be overwhelmed, and every time you reinstall the system will be a nightmare.
  3. I don’t want to compromise with my colleagues and want to use an editor I’m familiar with.
  4. Not satisfied with the official existing code tips, want to make their editor more intimate and intelligent.
To provide a more intimate development experience, Typescript Service Plugins are an official solution

Function orientation

The following is taken from the official WIKI:

In TypeScript 2.2 and later, developers can enable language service plugins to augment the TypeScript code editing experience.

As the official documentation makes clear, this is designed to optimize the experience of writing Typescript code. So if you want to use this to change compilation results or create your own syntax, save it. I’m talking about myself.

So what can Typescript Service Plugins do?

The official answer is clear:

plugins are for augmenting the editing experience. Some examples of things plugins might do:

  • Provide errors from a linter inline in the editor
  • Filter the completion list to remove certain properties from window
  • Redirect “Go to definition” to go to a different location for certain identifiers
  • Enable new errors or completions in string literals for a custom templating language

There are also official scenarios where Typescript Service Plugins are not recommended:

Examples of things language plugins cannot do:

  • Add new custom syntax to TypeScript
  • Change how the compiler emits JavaScript
  • Customize the type system to change what is or isn’t an error when running tsc

Now that you’ve read Typescript Service Plugins, I’m going to take a look at installing and using Typescript Service Plugins.

How do I install and configure Typescript Service Plugins

Install Typescript Service Plugins
Just like installing a normal 'NPM' package
npm install --save-dev your_plugin_name
Copy the code
How to configure Typescript Service Plugins in tsconfig.json
{
  "compilerOptions": {
    /** compilerOptions Configuration ... * /
    "noImplicitAny": true."plugins": [{/** Set the plug-in name. You can also enter the local path */
        "name": "sample-ts-plugin"
        /** The plugin can be passed as an argument... * /
      }
      /** Support to introduce multiple plug-ins at the same time... * /]}}Copy the code
A few caveats:
  1. If you are usingVSCodeDevelopment, be sureusing the workspace version of typescriptOtherwise, the plug-in may not take effect.
  2. Typescript Service PluginsThe generated alarm or error does not affect the compilation result.
  3. If it doesn’t work, try restarting your editor.

Examples of existing Typescript Service Plugins

For details, please open the demo PROVIDED by me in the editor and experience it by yourself.

Sample plug-in:typescript-plugin-css-modules

Plug-in installation
npm install --save-dev typescript-styled-plugin typescript
Copy the code
Configuration method
Add configuration in tsconfig.json
{
  "compilerOptions": {
    "plugins": [{"name": "typescript-styled-plugin"
        /** For specific configuration parameters, see the official document */}}}]Copy the code
Basic introduction and application scenarios of the plug-in

This plug-in can be used to alleviate the dilemma of using CSS Module without code prompt. The main idea is to read the corresponding CSS Module file and parse it into the corresponding AST, and generate the corresponding type file to support the corresponding code prompt. However, based on the feedback, it seems that some scenarios are not as good as they should be, and whether they are worth using on a large scale is questionable.

Typings-for-css-modules-loader is more powerful than Webpack loader, but Typescript Plugin is lighter and less intrusive

Sample plug-in:typescript-eslint-language-service

Plug-in installation
npm install --save-dev eslint typescript-eslint-language-service
Copy the code
Configuration method

In the.eslintrc.* file, add the corresponding ESLint configuration

Add configuration in tsconfig.json
{
  "compilerOptions": {
    "plugins": [{"name": "typescript-eslint-language-service"
        /** The.eslintrc.* 'file */ is read by default
        /** For specific configuration parameters, see the official document */}}}]Copy the code
Basic introduction and application scenarios of the plug-in

This plugin enables Typescript to support ESLint checking and alarms nandly. The editor does not need to install any plugins to support it, but errors do not affect compilation results.

Sample plug-in:typescript-styled-plugin

Plug-in installation
npm install --save-dev typescript-styled-plugin typescript
Copy the code
Configuration method
Add configuration in tsconfig.json
{
  "compilerOptions": {
    "plugins": [{"name": "typescript-styled-plugin"
        /** For specific configuration parameters, see the official document */}}}]Copy the code
Basic introduction and application scenarios of the plug-in

This plug-in provides property/property values for styled- Components style string templates for syntax checking. It is also recommended to install the VSCode plug-in vscode-Styled – Components, which provides code hints and syntax highlighting for your style string template.

How do I write Typescript Service Plugins myself

To be continued…

Resources link

  1. Using the Compiler API
  2. Using the Language Service API
  3. Writing a Language Service Plugin
  4. Useful Links for TypeScript Issue Management

conclusion

To be continued…

Q&A (welcome to comment section)

Can the Typescript Service Plugin (for example, configuring ESLint rules) be used to block compilations or generate compile-time alarms?

A: No, all situations in which Typescript plugins can be used must be at the coding stage, and plugins are only defined to improve the writing experience. You can’t customize the syntax or rules to change the compilation results. However, you could consider using a custom compiler, which is a topic for another day.

The following quotes are from official documentation:

TypeScript Language Service Plugins (“plugins”) are for changing the editing experience only. The core TypeScript language remains the same. Plugins can’t add new language features such as new syntax or different typechecking behavior, and plugins aren’t loaded during normal commandline typechecking or emitting.