Author: Attention 🐴
Github: Github
Nuggets: Go in and have a look 🐴
Hobbies: Americano More Ice!
An inside volume note about Typescript
- Typescript
- brief introduction
- install
- Write the first demo
- Basics
- Raw data type
- Arbitrary value
- type inference
- Union type
- Object type - Interface
- Array type
- Function type
- Type Assertion
- Declaration document
- New syntax index
- What is a declaration statement
- What is a declaration file
- Writing declaration documents
- UMD Library
- Direct extension of global variables
- Expand global variables in npm package or UMD Library
- Module plug-in
- Dependency in declaration file
- Automatic generation of declaration files
- Release statement document
- Built in object
- Advanced
- engineering
brief introduction
TypeScript is a superset of JavaScript types, which can be compiled into pure JavaScript. The compiled JavaScript can run on any browser. TypeScript compiler can run on any server and any system. TypeScript is open source.
install
npm install -g typescript
After installation, there will be a tsc global command
Write the first demo
// hello.ts function sayHello(person: string) { return 'Hello, ' + person; } let user = 'Tom'; console.log(sayHello(user));
Execute TSC hello TS, generate hello js
function sayHello(person) { return 'Hello, ' + person; } var user = 'Tom'; console.log(sayHello(user));
Compare the differences between the two:
- The parameters inserted in ts will have parameter types. ts will only perform static check. If an error is found, an error will be reported during compilation
- let is the keyword of ES6, similar to var, which is used to define a local variable
Basics
Raw data type
There are two types of JavaScript: Primitive data types and Object types.
Raw data types include Boolean, numeric, string, null, undefined, and the new type Symbol in ES6.
Boolean value
// Boolean is the basic type in JavaScript, and Boolean is the constructor in JavaScript let isDone: boolean = false; // A Boolean object is returned let createdByNewBoolean: Boolean = new Boolean(1); // Returns a boolean type let createdByBoolean: boolean = Boolean(1);
numerical value
// Where 0b1010 and 0o744 are binary and octal representations in ES6, which will be compiled into decimal numbers let decLiteral: number = 6; let hexLiternal: number = 0xf00d; // Binary representation in ES6 let binaryLiteral: number = 0b1010; // Octal notation in ES6 let octalLiteral: number = 0o744; let notANumber: number = NaN; let infinityNumber: number = Infinity;
character string
// `Used to define Template Strings, ${expr} is used to embed expressions let myName: string = 'Tom'; let myAge: number = 25; let sentence: string = `Hello, my name is ${myName}.I'll be ${myAge + 1} years old next day`;
Null value
// Indicates that there is no return value function alertName(): void { alert('My name is Tom'); } // It's no use declaring a variable of void type, because you can only assign it to undefined and null let unusable: void = undefined;
// Null and Undefined let u: undefined = undefined; let n: null = null; // The difference from void is that undefined and null are subtypes of all types // Variables of type undefined can be assigned to variables of type number let num: number = undefined; // perhaps let u: undefined; let num: number = u; // And void can't let u: void; let num: number = u; // Type 'void' is not assignable to type 'number'.
Arbitrary value
Arbitrary value (Any) is used to indicate that assignment to Any type is allowed
After declaring a variable as an arbitrary value, the type of content returned by any operation on it is an arbitrary value
// usage let myFavoriteNumber: any = 'seven'; myFavoriteNumber = 7; // Access any properties let anyThing: any = 'hello'; console.log(anyThing.myName); console.log(anyThing.myName.firstName); // Call any method let anyThing: any = 'Tom'; anyThing.setName('Jerry'); anyThing.setName('Jerry').sayHello(); anyThing.myName.setFirstName('Cat');
If a variable is declared without specifying its type, it will be recognized as any value type
// let something: any; let something; something = 'seven'; something = 7; something.setName('Tom');
type inference
TypeScript will infer a type when there is no explicit specified type, which is type inference
// If no type is specified, but the assignment is string, it is considered as string type // Compilation error let myFavoriteNumber = 'seven'; myFavoriteNumber = 7; // If there is no assignment at the time of definition, it will be inferred as any type regardless of whether there is assignment later // Not type checked at all let myFavoriteNumber; myFavoriteNumber = 'seven'; myFavoriteNumber = 7;
Union type
Union Types means that the value can be one of multiple types
// Union types use | to separate each type // Correct. myFavoriteNumber is allowed to be of type string or number, but not of other types let myFavoriteNumber: string | number; myFavoriteNumber = 'seven'; myFavoriteNumber = 7; // report errors let myFavoriteNumber: string | number; myFavoriteNumber = true;
When TypeScript does not know which type the variable of a union type is, we can only access the properties or methods common to all types of the union type
// length is not a common attribute of string and number, so an error will be reported function getLength(something: string | number): number { return something.length; } // index.ts(2,22): error TS2339: Property 'length' does not exist on type 'string | number'. // Property 'length' does not exist on type 'number'.
There is no problem accessing the common properties of string and number
function getString(something: string | number): string { return something.toString(); }
When a variable of joint type is assigned a value, it will infer a type according to the rules of type inference
let myFavoriteNumber: string | number; myFavoriteNumber = 'seven'; // Inferred as string console.log(myFavoriteNumber.length); // 5 // Inferred as number myFavoriteNumber = 7; console.log(myFavoriteNumber.length); // Compile error
Object type - Interface
In TypeScript, we use Interfaces to define the type of objects.
- What is an interface
In object-oriented language, Interfaces is a very important concept. It is the abstraction of behavior, and how to act needs to be implement ed by classes.
The interface in TypeScript is a very flexible concept. In addition to abstracting part of the behavior of a class, it is also commonly used to describe the "Shape of an object".
interface Person { name: string; age: number; } // tom, whose type is Person, constrains that the shape of tom must be consistent with the interface Person // That is, the number and type of attributes should be consistent let tom: Person = { name: 'Tom', age: 25 };
- optional attribute
If you do not want to match a shape exactly, you can use the following optional attributes:
interface Person { name: string; age?: number; } // Optional attribute age, free or nonexistent let tom: Person = { name: 'Tom' };
- Arbitrary attribute
An interface is allowed to have any attributes. The following methods can be used
interface Person { name: string; age?: number; [propName: string]: any; } let tom: Person = { name: 'Tom', gender: 'male' };
Note: once any attribute is defined, the type of the determined attribute and the optional attribute must be a subset of its type:
interface Person { name: string; age?: number; [propName: string]: string; } // An error is reported. age is not a string let tom: Person = { name: 'Tom', age: 25, gender: 'male' }; // Use union type in any attribute to solve the above problem interface Person { name: string; age?: number; [propName: string]: string | number; } let tom: Person = { name: 'Tom', age: 25, gender: 'male' };
- Read only attribute
Sometimes we want some fields in the object to be assigned only when it is created, so we can use readonly to define the read-only attribute
interface Person { readonly id: number; name: string; age?: number; [propName: string]: any; } let tom: Person = { id: 89757, name: 'Tom', gender: 'male' }; // An error is reported because the property is read-only tom.id = 9527;
Note that the read-only constraint exists when the object is assigned a value for the first time, not when the read-only attribute is assigned a value for the first time
interface Person { readonly id: number; name: string; age?: number; [propName: string]: any; } // The first error is reported and the id is not assigned let tom: Person = { name: 'Tom', gender: 'male' }; // The second error is reported because it is read-only tom.id = 89757;
Array type
In TypeScript, array types can be defined in many ways
For example:
let fibonacci: number[] = [1, 1, 2, 3, 5];
No other types are allowed in the items of the array
let fibonacci: number[] = [1, '1', 2, 3, 5]; // Type 'string' is not assignable to type 'number'.
The parameters of some methods of the array will also be limited according to the types agreed upon when the array is defined
let fibonacci: number[] = [1, 1, 2, 3, 5]; fibonacci.push('8'); // Argument of type '"8"' is not assignable to parameter of type 'number'.
- Array generic
Array < ElemType > to represent the array
let fibonacci: Array<number> = [1, 1, 2, 3, 5];
- Interface representation array
// NumberArray means that as long as the type of index is number, the type of value must be number interface NumberArray { [index: number]: number; } let fibonacci: NumberArray = [1, 1, 2, 3, 5];
- Array like object
Array like objects are not array types, such as arguments
function sum() { let args: number[] = arguments; } // It can't be described by ordinary array, but by interface // Value must be of type other than number // It also has two attributes: length and callee function sum() { let args: { [index: number]: number; length: number; callee: Function; } = arguments; }
In fact, commonly used class arrays have their own interface definitions, such as iargements, NodeList, htmlcollection, etc
function sum() { let args: IArguments = arguments; } // Iargements are types defined in TypeScript interface IArguments { [index: number]: any; length: number; callee: Function; }
- Application of any in array
A common practice is to use any to indicate that any type is allowed in the array
let list: any[] = ['xiaobiao', 25, { website: 'http://xcatliu.com' }];
Function type
In JavaScript, there are two common ways to define functions
- Function Declaration
- Function Expression
// Function Declaration function sum(x, y) { return x + y; } // Function Expression let mySum = function (x, y) { return x + y; };
- Function declaration
ts is slightly different in that it uses constraints
function sum(x: number, y: number): number { return x + y; } // It is not allowed to enter redundant (or less than required) parameters // report errors sum(1, 2, 3); sum(1); // correct sum(1,2)
- Function expression
In the type definition of TypeScript, = > is used to represent the definition of function. On the left is the input type, which needs to be enclosed in parentheses, and on the right is the output type.
In ES6, = > is called arrow function, which is widely used
let mySum = function (x: number, y: number): number { return x + y; }; // The above code only defines the type of anonymous functions on the right side of the equal sign, while mySum on the left side of the equal sign is inferred by type inference through assignment operation // If you manually add a type to mySum, this should be the case let mySum: (x: number, y: number) => number = function (x: number, y: number): number { return x + y; };
- Defining the shape of a function with an interface
interface SearchFunc { (source: string, subString: string): boolean; } let mySearch: SearchFunc; mySearch = function(source: string, subString: string) { return source.search(subString) !== -1; }
- Optional parameters
function buildName(firstName: string, lastName?: string) { if (lastName) { return firstName + ' ' + lastName; } else { return firstName; } } let tomcat = buildName('Tom', 'Cat'); let tom = buildName('Tom');
Required parameters are not allowed after optional parameters
function buildName(firstName?: string, lastName: string) { if (firstName) { return firstName + ' ' + lastName; } else { return lastName; } } let tomcat = buildName('Tom', 'Cat'); let tom = buildName(undefined, 'Tom'); // index.ts(1,40): error TS1016: A required parameter cannot follow an optional parameter.
- Parameter defaults
TypeScript recognizes parameters with default values as optional:
function buildName(firstName: string, lastName: string = 'Cat') { return firstName + ' ' + lastName; } let tomcat = buildName('Tom', 'Cat'); let tom = buildName('Tom');
Not limited by "optional parameters must be followed by required parameters":
function buildName(firstName: string = 'Tom', lastName: string) { return firstName + ' ' + lastName; } let tomcat = buildName('Tom', 'Cat'); let cat = buildName(undefined, 'Cat');
- Residual parameters
function push(array: any[], ...items: any[]) { items.forEach(function(item) { array.push(item); }); } let a = []; push(a, 1, 2, 3);
- heavy load
Overloading allows a function to do different things when it accepts different numbers or types of parameters.
function reverse(x: number): number; function reverse(x: string): string; function reverse(x: number | string): number | string { if (typeof x === 'number') { return Number(x.toString().split('').reverse().join('')); } else if (typeof x === 'string') { return x.split('').reverse().join(''); } }
Type Assertion
Type assertions can be used to manually specify the type of a value
Syntax:
Value as type or < type > value, the former is recommended
Type assertion purpose
- Assert a union type as one of the types
// The reason is (animal as Fish) The code of swim () hides the possibility that animal may be Cat and directly asserts animal as Fish // The TypeScript compiler trusted our assertion, so there were no compilation errors when calling swim() interface Cat { name: string; run(): void; } interface Fish { name: string; swim(): void; } function swim(animal: Cat | Fish) { (animal as Fish).swim(); } const tom: Cat = { name: 'Tom', run() { console.log('run') } }; swim(tom); // Uncaught TypeError: animal.swim is not a function`
- Assert a parent class as a more specific subclass
interface type can only use type assertion to judge whether code is AirError
class type can be instanceof
class ApiError extends Error { code: number = 0; } class HttpError extends Error { statusCode: number = 200; } function isApiError(error: Error) { if (typeof (error as ApiError).code === 'number') { // Here is a more appropriate approach // Indeed, instanceof is more appropriate, because ApiError is a JavaScript class, which can judge whether error is its instance through instanceof // if (error instanceof ApiError) { return true; } return false; }
- Assert any type as any
It's very likely to cover up real type errors, so don't use as any if you're not very sure
Syntax: (window as any) foo = 1;
- Assert any as a concrete type
It is better to assert the return value after calling it into a precise type, which facilitates subsequent operations (improve maintainability)
function getCacheData(key: string): any { return (window as any).cache[key]; } interface Cat { name: string; run(): void; } const tom = getCacheData('tom') as Cat; tom.run();
Restriction on the type of assertion
- A union type can be asserted as one of these types
- A parent class can be asserted as a child class
- Any type can be asserted as any
- Any can be asserted as any type
- To enable A to be asserted as B, only A is compatible with B or B is compatible with A
When Animal is Cat compatible, they can type assert each other
interface Animal { name: string; } interface Cat { name: string; run(): void; } function testAnimal(animal: Animal) { return (animal as Cat); } function testCat(cat: Cat) { return (cat as Animal); }
Double assertion
Never use double assertions unless you have to
Type assertion vs type conversion
Type assertion is not a type conversion, it does not really affect the type of variable
To perform type conversion, you need to call the method of type conversion directly
function toBoolean(something: any): boolean { return Boolean(something); } toBoolean(1); // The return value is true
Type assertion vs type declaration
interface Animal { name: string; } interface Cat { name: string; run(): void; } const animal: Animal = { name: 'tom' }; // Since animal is Cat compatible, it is possible to assign an animal assertion as Cat to tom let tom = animal as Cat; // let tom: Cat = animal; report errors // Animal can be regarded as the parent class of Cat. Of course, the instance of the parent class cannot be assigned to a variable of type subclass.
If Animal is asserted as Cat, it only needs to meet the requirements of Animal compatible Cat or Cat compatible Animal.
The assignment of "Animal" to "tom" needs to be Cat compatible with "Animal"
To sum up, type declarations are more rigorous and elegant than type assertions
Type assertion vs generics
Before modification
function getCacheData(key: string): any { return (window as any).cache[key]; } interface Cat { name: string; run(): void; } const tom = getCacheData('tom') as Cat; tom.run();
After modification
function getCacheData<T>(key: string): T { return (window as any).cache[key]; } interface Cat { name: string; run(): void; } const tom = getCacheData<Cat>('tom'); tom.run();
By adding a generic < T > to the getCacheData function, we can more standardize the constraint on the return value of getCacheData, which also removes any in the code. It is an optimal solution.
Declaration document
When using a third-party library, we need to reference its declaration file to obtain the corresponding code completion, interface prompt and other functions
New syntax index
`declare var` Declare global variables `declare function` Declare global methods `declare class` Declare global class `declare enum` Declare global enumeration type `declare namespace` Declare a global object (with child attributes) `interface` and type Declare global type `export` Export variables `export namespace` Export (objects with child attributes) `export default` ES6 Default export `export =` commonjs Export module `export as namespace` UMD Library declaration global variables `declare global` Extended global variable `declare module` Expansion module `///< reference / > ` three slash instruction
What is a declaration statement
If we want to use a third-party library jQuery, a common way is to introduce jQuery through the script tag in html, and then we can use the global variable $or jQuery.
// declare var does not really define a variable, but defines the type of global variable jQuery // It will only be used for compile time checking and will be deleted in the compilation results declare var jQuery: (selector: string) => any; jQuery('#foo');
After compilation: jQuery('#foo');
What is a declaration file
Usually we put the declaration statements in a separate file (jQuery.d.ts), which is the declaration file
// src/jQuery.d.ts declare var jQuery: (selector: string) => any; // src/index.ts jQuery('#foo');
The declaration file must be in d.ts is suffix
Generally speaking, ts will parse all *. In the project ts file, of course, also contains d. File at the end of ts. So when we put jQuery d. When ts is placed in the project, all other * The type definition of jQuery can be obtained from the ts file
/path/to/project ├── src | ├── index.ts | └── jQuery.d.ts └── tsconfig.json
If it still cannot be parsed, you can check tsconfig Configure files, include, and exclude in JSON to ensure that it contains jQuery d. TS file
Third party declaration document
It is recommended to use @ types to uniformly manage the declaration files of third-party libraries.
@The use of types is very simple. You can directly install the corresponding declaration module with npm, such as
npm install @types/jquery --save-dev
Writing declaration documents
global variable
When using the declaration file of global variables, if it is installed as NPM install @ types / xxx -- save dev, no configuration is required. If the declaration file is stored directly in the current project, it is recommended that (jQuery.d.ts) and other source code be placed in the src directory (or the corresponding source code directory)
The declaration files of global variables mainly have the following syntax:
`declare var` Declare global variables `declare function` Declare global methods `declare class` Declare global class `declare enum` Declare global enumeration type `declare namespace` Declare a global object (with child attributes) `interface and type` Declare global type
declare var
Generally speaking, global variables are constants that cannot be modified, so const should be used instead of var or let in most cases.
// src/jQuery.d.ts declare const jQuery: (selector: string) => any; // jQuery('#foo'); // Using the jQuery type defined by declare const, it is forbidden to modify this global variable // ERROR: Cannot assign to 'jQuery' because it is a constant or a read-only property. jQuery = function(selector) { return document.querySelector(selector); }; // Note: only types can be defined in the declaration statement. Do not define specific implementations in the declaration statement // declare const jQuery = function(selector) { // return document.querySelector(selector); // }; // ERROR: An implementation cannot be declared in ambient contexts.
declare function
The type used to define the global function. jQuery is actually a function, so it can also be defined by function
example:
// src/jQuery.d.ts declare function jQuery(selector: string): any; // src/index.ts jQuery('#foo');
Function overloading is also supported in the declaration statement of function type
// src/jQuery.d.ts declare function jQuery(selector: string): any; declare function jQuery(domReadyCallback: () => any): any; // src/index.ts jQuery('#foo'); jQuery(function() { alert('Dom Ready!'); });
declare class
When a global variable is a class, we use declare class to define its type
example:
// src/Animal.d.ts declare class Animal { name: string; constructor(name: string); sayHi(): string; } // src/index.ts let cat = new Animal('Tom');
The declare class statement can only be used to define the type (and so can declare var). It cannot be used to define the specific implementation. For example, if you define the specific implementation of sayHi method, an error will be reported
Error example:
// src/Animal.d.ts declare class Animal { name: string; constructor(name: string); sayHi() { return `My name is ${this.name}`; }; // ERROR: An implementation cannot be declared in ambient contexts. }
declare enum
Enumeration types defined with declare enum are also called Ambient Enums
// src/Directions.d.ts declare enum Directions { Up, Down, Left, Right } // src/index.ts let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right]
declare namespace
Namespace is a keyword created by ts to solve modularization in the early days. It is called namespace in Chinese
JQuery is a global variable. It is an object that provides a jQuery Ajax methods can be called, so we should use declare namespace jQuery to declare this global variable with multiple sub attributes
Within declare namespace, we directly use function ajax to declare functions instead of declare function ajax. Similarly, const, class, enum and other statements can be used
// src/jQuery.d.ts declare namespace jQuery { function ajax(url: string, settings?: any): void; const version: number; class Event { blur(eventType: EventType): void } enum EventType { CustomClick } } // src/index.ts jQuery.ajax('/api/get_something'); console.log(jQuery.version); const e = new jQuery.Event(); e.blur(jQuery.EventType.CustomClick);
interface and type
In the type declaration file, we can directly use interface or type to declare a global interface or type
// src/jQuery.d.ts interface AjaxSettings { method?: 'GET' | 'POST' data?: any; } declare namespace jQuery { function ajax(url: string, settings?: AjaxSettings): void; } // src/index.ts let settings: AjaxSettings = { method: 'POST', data: { name: 'foo' } }; jQuery.ajax('/api/post_something', settings);
Prevent naming conflicts
The interface or type exposed in the outermost layer will act as a global type in the whole project. We should reduce the number of global variables or global types as much as possible. So it's best to put them under namespace
Declaration merge
// src/jQuery.d.ts declare function jQuery(selector: string): any; declare namespace jQuery { function ajax(url: string, settings?: any): void; } // src/index.ts jQuery('#foo'); jQuery.ajax('/api/get_something');
npm package
The declaration file of npm package mainly has the following syntax:
export Export variables export namespace Export (objects with child attributes) export default ES6 Default export export = commonjs Export module
export
The declaration file of npm package is very different from that of global variables. In the declaration file of npm package, declare will no longer declare a global variable, but only declare a local variable in the current file. These type declarations are not applied until export is used in the declaration file and then imported by the user import
// types/foo/index.d.ts export const name: string; export function getName(): string; export class Animal { constructor(name: string); sayHi(): string; } export enum Directions { Up, Down, Left, Right } export interface Options { data: any; }
The corresponding import and use modules should be as follows:
import { name, getName, Animal, Directions, Options } from 'foo'; console.log(name); let myName = getName(); let cat = new Animal('Tom'); let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right]; let options: Options = { data: { name: 'foo' } };
Mix declare and export
declare multiple variables first, and then export them at one time
// types/foo/index.d.ts declare const name: string; declare function getName(): string; declare class Animal { constructor(name: string); sayHi(): string; } declare enum Directions { Up, Down, Left, Right } interface Options { data: any; } export { name, getName, Animal, Directions, Options };
Note: declare is not required before the interface
export namespace
export namespace is used to export an object with sub attributes
// types/foo/index.d.ts export namespace foo { const name: string; namespace bar { function baz(): string; } }
// src/index.ts import { foo } from 'foo'; console.log(foo.name); foo.bar.baz();
export default
In the ES6 module system, export default can be used to export a default value. The user can import this default value with import foo from 'foo' instead of import {foo} from 'foo'
Only function, class and interface can be exported directly by default. Other variables need to be defined first and then exported by default
// types/foo/index.d.ts export default function foo(): string;
// src/index.ts import foo from 'foo'; foo();
For other default exports, the export statement is usually placed at the front of the whole declaration file
export default Directions; declare enum Directions { Up, Down, Left, Right }
export =
In the commonjs specification, we export a module in the following way
// Overall export module.exports = foo; // Single export exports.bar = bar;
In ts, there are many ways to export this module. The first way is const= require
// Overall import const foo = require('foo'); // Single import const bar = require('foo').bar;
The second way is to import From. Note that for overall export, you need to use import * as to import
// Overall import import * as foo from 'foo'; // Single import import { bar } from 'foo';
The third way is to import Require, which is also the official recommended method of ts
// Overall import import foo = require('foo'); // Single import import bar = foo.bar;
For this library using the commonjs specification, if you want to write a type declaration file for it, you need to use the syntax of export = for it
// types/foo/index.d.ts export = foo; declare function foo(): string; declare namespace foo { const bar: number; }
UMD Library
export as namespace
Generally, when using export as namespace (function: to declare additional global variables), you first have the declaration file of npm package, and then add an export as namespace statement based on it to declare a declared variable as a global variable, for example:
// types/foo/index.d.ts export as namespace foo; // export default foo; export = foo; declare function foo(): string; declare namespace foo { const bar: number; }
Direct extension of global variables
Some third-party libraries extend a global variable, but the type of the global variable is not updated accordingly, which will lead to ts compilation errors. At this time, it is necessary to extend the type of the global variable. For example, extend the String type
interface String { prependHello(): string; } 'foo'.prependHello();
You can also use declare namespace to add type declarations to existing namespaces
// types/jquery-plugin/index.d.ts declare namespace JQuery { interface CustomOptions { bar: string; } } interface JQueryStatic { foo(options: JQuery.CustomOptions): string; }
// src/index.ts jQuery.foo({ bar: '' });
Expand global variables in npm package or UMD Library
declare global
The type of global variable can be extended in the declaration file of npm package or UMD library
// types/foo/index.d.ts declare global { interface String { prependHello(): string; } } // Note that even if this declaration file does not need to export anything, it still needs to export an empty object to tell the compiler that this is a module declaration file // Instead of a declaration file for a global variable export {};
// src/index.ts 'bar'.prependHello();
Module plug-in
ts provides a syntax declare module, which can be used to extend the type of the original module
// types/moment-plugin/index.d.ts import * as moment from 'moment'; declare module 'moment' { export function foo(): moment.CalendarKey; }
// src/index.ts import * as moment from 'moment'; import 'moment-plugin'; moment.foo();
You can also declare multiple module types in a single file
// types/foo-bar.d.ts declare module 'foo' { export interface Foo { foo: string; } } declare module 'bar' { export function bar(): string; }
// src/index.ts import { Foo } from 'foo'; import * as bar from 'bar'; let f: Foo; bar.bar();
Dependency in declaration file
A declaration file sometimes depends on the type in another declaration file. For example, in the previous example of declare module, we imported moment in the declaration file and used moment Calendarkey this type
// types/moment-plugin/index.d.ts import * as moment from 'moment'; declare module 'moment' { export function foo(): moment.CalendarKey; }
Triple slash instruction
Similar to import in the declaration file, it can be used to import another declaration file. The difference from import is that we need to use the triple slash instruction instead of import only in the following scenarios:
- When we are writing a declaration file for a global variable
- When we need to rely on the declaration file of a global variable
Write a declaration file for a global variable
These scenarios sound awkward, but they are actually easy to understand - the import and export keywords are not allowed in the declaration file of global variables. Once it appears, it will be regarded as an npm package or UMD library, which is no longer the declaration file of global variables. Therefore, when we write the declaration file of a global variable, if we need to refer to the type of another library, we must use the triple slash instruction
// types/jquery-plugin/index.d.ts /// <reference types="jquery" /> declare function foo(options: JQuery.AjaxSettings): string;
// src/index.ts foo({});
The syntax of the triple slash instruction is as above, and the xml format is used after / / / to add the dependency on the jquery type, so that jquery can be used in the declaration file Ajax settings type
Note that the triple slash instruction must be placed at the top of the file, and only one or more lines of comments are allowed in front of the triple slash instruction
A declaration file that depends on a global variable
In another scenario, when we need to rely on the declaration file of a global variable, because the global variable does not support import, of course, we must use the triple slash instruction to import
// types/node-plugin/index.d.ts /// <reference types="node" /> export function foo(p: NodeJS.Process): string;
// types/node-plugin/index.d.ts /// <reference types="node" /> export function foo(p: NodeJS.Process): string;
Split declaration file
When the declaration file of our global variable is too large, we can improve the maintainability of the code by splitting it into multiple files and introducing them one by one in an entry file. For example, jQuery's declaration file is like this
// node_modules/@types/jquery/index.d.ts /// <reference types="sizzle" /> /// <reference path="JQueryStatic.d.ts" /> /// <reference path="JQuery.d.ts" /> /// <reference path="misc.d.ts" /> /// <reference path="legacy.d.ts" /> export = jQuery;
Automatic generation of declaration files
Method 1: syntax TSC XX ts -d or tsc xx. ts --declaration
The difference is that types is used to declare a dependency on another library, while path is used to declare a dependency on another file
Method 2: in tsconfig Add the declaration option to JSON. Here, use tsconfig JSON as an example
{ "compilerOptions": { "module": "commonjs", "outDir": "lib", "declaration": true } }
Release statement document
After we have written the declaration file for a library, the next step is to publish it.
There are two options:
- Put the declaration file and source code together
- Publish the declaration file to @ types
Built in object
There are many built-in objects in JavaScript, which can be directly used as defined types in TypeScript.
Built in objects are objects that exist on the Global scope according to the standard. The standard here refers to the standard of ECMAScript and other environments (such as DOM)
Built in object of ECMAScript
The built-in objects provided by ECMAScript standard include:
Boolean, Error, Date, RegExp, etc.
let b: Boolean = new Boolean(1); let e: Error = new Error('Error occurred'); let d: Date = new Date(); let r: RegExp = /[a-z]/;
More built-in objects
Core library definition
DOM and BOM built-in objects
Built in objects provided by DOM and BOM include:
Document, HTMLElement, Event, NodeList, etc.
// Commonly used let body: HTMLElement = document.body; let allDiv: NodeList = document.querySelectorAll('div'); document.addEventListener('click', function(e: MouseEvent) { // Do something });
Definition file of TypeScript core library
The definition file of TypeScript core library defines the types required by all browser environments, and is preset in TypeScript.
Write node with TypeScript js
Node.js is not part of the built-in object. If you want to write node with TypeScript JS, you need to import a third-party declaration file:
npm install @types/node --save-dev
Advanced
Type alias
Commonly used for union types
type Name = string; type NameResolver = () => string; type NameOrResolver = Name | NameResolver; function getName(n: NameOrResolver): Name { if (typeof n === 'string') { return n; } else { return n(); } }
String literal type
String literal type is used to restrict that the value can only be one of several strings.
type EventNames = 'click' | 'scroll' | 'mousemove'; function handleEvent(ele: Element, event: EventNames) { // do something } handleEvent(document.getElementById('hello'), 'scroll'); // no problem handleEvent(document.getElementById('world'), 'dblclick'); // An error is reported. event cannot be 'dblclick' // index.ts(7,47): error TS2345: Argument of type '"dblclick"' is not assignable to parameter of type 'EventNames'.
Note that both type aliases and string literal types are defined using type.
tuple
Arrays combine objects of the same type, while tuples combine objects of different types.
Tuples originate from functional programming languages (such as F#), in which tuples are frequently used
let tom: [string, number]; tom[0] = 'Tom'; tom[1] = 25; tom[0].slice(1); tom[1].toFixed(2);
Out of bounds array: when an out of bounds element is added, its type is limited to the union type of each type in the tuple
let tom: [string, number]; tom = ['Tom', 25]; tom.push('male'); tom.push(true); // Argument of type 'true' is not assignable to parameter of type 'string | number'.
enumeration
Enum type is used for scenes whose values are limited to a certain range. For example, there can only be seven days a week, and the color is limited to red, green and blue
Enum members are assigned a number that increases from 0, and the enum value is inversely mapped to the enum name
enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat}; console.log(Days["Sun"] === 0); // true console.log(Days["Mon"] === 1); // true console.log(Days["Tue"] === 2); // true console.log(Days["Sat"] === 6); // true console.log(Days[0] === "Sun"); // true console.log(Days[1] === "Mon"); // true console.log(Days[2] === "Tue"); // true console.log(Days[6] === "Sat"); // true
Manual assignment
TypeScript will not notice if the enumeration item that is not manually assigned repeats the enumeration item that is manually assigned
enum Days {Sun = 3, Mon = 1, Tue, Wed, Thu, Fri, Sat}; console.log(Days["Sun"] === 3); // true console.log(Days["Wed"] === 3); // true console.log(Days[3] === "Sun"); // false console.log(Days[3] === "Wed"); // true
The enumeration item manually assigned can not be a number. In this case, you need to use type assertion to make tsc ignore type checking (the compiled js is still available):
enum Days {Sun = 7, Mon, Tue, Wed, Thu, Fri, Sat = <any>"S"};
Enumeration items with manual assignment can also be decimal or negative. At this time, the increment step of subsequent items without manual assignment is still 1
enum Days {Sun = 7, Mon = 1.5, Tue, Wed, Thu, Fri, Sat}; console.log(Days["Sun"] === 7); // true console.log(Days["Mon"] === 1.5); // true console.log(Days["Tue"] === 2.5); // true console.log(Days["Sat"] === 6.5); // true
Constant term and calculated term
There are two types of enumeration items: constant member and calculated member
// Correct example enum Color {Red, Green, Blue = "blue".length}; // Error example // If the calculated item is followed by an item that has not been manually assigned, it will report an error because it cannot obtain the initial value enum Color {Red = "red".length, Green, Blue}; // index.ts(1,33): error TS1061: Enum member must have initializer. // index.ts(1,40): error TS1061: Enum member must have initializer.
Enumeration members are treated as constants when the following conditions are met:
Does not have an initialization function and the previous enumeration member is a constant. In this case, the value of the current enumeration member is the value of the previous enumeration member plus 1. The first enumeration element is an exception. If it has no initialization method, its initial value is 0.
Enumeration members are initialized with constant enumeration expressions. Constant enumeration expressions are a subset of TypeScript expressions that can be evaluated at compile time. When an expression satisfies one of the following conditions, it is a constant enumeration expression:
Numeric literal
Reference the previously defined constant enumeration member (which can be defined in different enumeration types). If this member is defined in the same enumeration type, it can be referenced with an unqualified name
Parenthesized constant enumeration expression
+, -, ~ unary operators apply to constant enumeration expressions
+, -, *, /,%, <, > >, > >, &, |, ^ binary operator, constant enumeration expression as one of its operands. If the constant enumeration expression evaluates to NaN or Infinity, an error will be reported at the compilation stage
Enumeration members in all other cases are treated as values that need to be calculated.
Constant enumeration
const enum Directions { Up, Down, Left, Right } let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
The difference between constant enumeration and ordinary enumeration is that it will be deleted at the compilation stage and cannot contain calculated members.
If a calculated member is included, an error will be reported at the compilation stage:
const enum Color {Red, Green, Blue = "blue".length}; // index.ts(1,38): error TS2474: In 'const' enum declarations member initializer must be constant expression.
External enums (Ambient Enums)
declare enum Directions { Up, Down, Left, Right } let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
It is also possible to use declare and const at the same time:
declare const enum Directions { Up, Down, Left, Right } let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
class
Concept of class
- Class( Class): It defines the abstract characteristics of a thing, including its attributes and methods - Object( Object): Class through new generate - Object oriented( OOP)Three characteristics of: encapsulation, inheritance and polymorphism - Encapsulation( Encapsulation): Hide the details of data operation and only expose the external interface. The external caller does not need (and cannot) know the details, and can access the object through the interface provided externally. At the same time, it also ensures that the external cannot arbitrarily change the internal data of the object - Inherit( Inheritance): Subclasses inherit the parent class. In addition to all the characteristics of the parent class, subclasses also have some more specific characteristics - Polymorphism( Polymorphism): Different classes are generated by inheritance, and they can have different responses to the same method. such as Cat and Dog All inherited from Animal,But they have achieved their own goals eat method. At this point, for an instance, we do not need to know whether it is Cat still Dog,You can call it directly eat Method, the program will automatically determine how to execute it eat - Accessor( getter & setter): Used to change the reading and assignment behavior of attributes - Modifier( Modifiers): Modifiers are keywords that qualify the nature of a member or type. such as public Represents a public property or method - Abstract class( Abstract Class): Abstract classes are base classes inherited by other classes. Abstract classes are not allowed to be instantiated. Abstract methods in abstract classes must be implemented in subclasses - Interface( Interfaces): Public attributes or methods between different classes can be abstracted into an interface. Interfaces can be implemented by classes( implements). A class can only inherit from another class, but can implement multiple interfaces
Usage of ES6 class
Properties and methods
Use class to define the class and constructor to define the constructor.
When a new instance is generated through new, the constructor will be called automatically
class Animal { public name; constructor(name) { this.name = name; } sayHi() { return `My name is ${this.name}`; } } let a = new Animal('Jack'); console.log(a.sayHi()); // My name is Jack
Class inheritance
Use the extends keyword to implement inheritance, and use the super keyword in the subclass to call the constructor and method of the parent class
class Cat extends Animal { constructor(name) { super(name); // Call the constructor(name) of the parent class console.log(this.name); } sayHi() { return 'Meow, ' + super.sayHi(); // Call sayHi() of the parent class } } let c = new Cat('Tom'); // Tom console.log(c.sayHi()); // Meow, My name is Tom
Accessor
Using getter s and setter s, you can change the assignment and reading behavior of attributes
class Animal { constructor(name) { this.name = name; } get name() { return 'Jack'; } set name(value) { console.log('setter: ' + value); } } let a = new Animal('Kitty'); // setter: Kitty a.name = 'Tom'; // setter: Tom console.log(a.name); // Jack
Static method
Methods decorated with static modifiers are called static methods. They do not need to be instantiated, but are called directly through classes
class Animal { static isAnimal(a) { return a instanceof Animal; } } let a = new Animal('Jack'); Animal.isAnimal(a); // true a.isAnimal(a); // TypeError: a.isAnimal is not a function
Usage of ES7 class
Instance properties
The attribute of an instance in ES6 can only be passed through this. In the constructor XXX, which can be defined directly in the class in ES7 proposal
class Animal { name = 'Jack'; constructor() { //... } } let a = new Animal(); console.log(a.name); //Jack
Static properties
In the ES7 proposal, static can be used to define a static attribute
class Animal { static num = 42; constructor() { // ... } } console.log(Animal.num); //42
Usage of TypeScript class
public private and protected
- The properties or methods modified by public are public and can be accessed anywhere. By default, all properties and methods are public
- The property or method of private modification is private and cannot be accessed outside the class that declares it
- The protected modified attribute or method is protected. It is similar to private, except that it is also allowed to be accessed in subclasses
Parameter properties
Modifiers and readonly can also be used in constructor parameters, which is equivalent to defining the attribute in the class and assigning a value to the attribute to make the code more concise
class Animal { // public name: string; public constructor(public name) { // this.name = name; } }
readonly
Read only attribute keyword, only allowed in attribute declaration or index signature or constructor
class Animal { readonly name; public constructor(name) { this.name = name; } } let a = new Animal('Jack'); console.log(a.name); // Jack a.name = 'Tom'; // index.ts(10,3): TS2540: Cannot assign to 'name' because it is a read-only property.
It will be more elegant to write like this
class Animal { // public readonly name; public constructor(public readonly name) { // this.name = name; } }
abstract class
Abstract is used to define abstract classes and abstract methods in them
Abstract classes are not allowed to be instantiated, ex:
abstract class Animal { public name; public constructor(name) { this.name = name; } public abstract sayHi(); } let a = new Animal('Jack'); // index.ts(9,11): error TS2511: Cannot create an instance of the abstract class 'Animal'.
Abstract methods in abstract classes must be implemented by subclasses, ex:
abstract class Animal { public name; public constructor(name) { this.name = name; } public abstract sayHi(); } // Subclasses implement abstract classes class Cat extends Animal { public sayHi() { console.log(`Meow, My name is ${this.name}`); } } let cat = new Cat('Tom');
Type of class
Adding TypeScript types to classes is simple, similar to interfaces
class Animal { name: string; constructor(name: string) { this.name = name; } sayHi(): string { return `My name is ${this.name}`; } } let a: Animal = new Animal('Jack'); console.log(a.sayHi()); // My name is Jack
Classes and interfaces
Class implementation interface
Implementation is an important concept in object-oriented. There can be some common features between different classes. At this time, the features can be extracted into interfaces and implemented with the keyword implements. This feature greatly improves object-oriented flexibility.
For example, a door is a class, and an anti-theft door is a subclass of a door. If the anti-theft door has the function of an alarm, we can simply add an alarm method to the anti-theft door. At this time, if there is another class, car, which also has the function of alarm, you can consider extracting the alarm as an interface, which can be realized by both anti-theft door and car. ex:
interface Alarm { alert(): void; } class Door { } class SecurityDoor extends Door implements Alarm { alert() { console.log('SecurityDoor alert'); } } class Car implements Alarm { alert() { console.log('Car alert'); } }
A class implements multiple interfaces
interface Alarm { alert(): void; } interface Light { lightOn(): void; lightOff(): void; } class Car implements Alarm, Light { alert() { console.log('Car alert'); } lightOn() { console.log('Car light on'); } lightOff() { console.log('Car light off'); } }
Interface inheritance interface
LightableAlarm inherits Alarm and has two new methods, lightOn and lightOff, in addition to the alert method.
interface Alarm { alert(): void; } interface LightableAlarm extends Alarm { lightOn(): void; lightOff(): void; }
Interface inheritance class
In common object-oriented languages, interfaces cannot inherit classes, but they can in TypeScript f
- Class can be used as a class (new xx creates its instance)
- Class can be used as a type (use: xx to indicate the type of parameter)
interface PointInstanceType { x: number; y: number; } // Equivalent to class Point { x: number; y: number; constructor(x: number, y: number) { this.x = x; this.y = y; } }
When we declare interface Point3d extends Point, Point3d actually inherits the type of the instance of Point class.
In other words, it can be understood that one interface Point3d inherits another interface PointInstanceType.
Therefore, there is no essential difference between "interface inheritance class" and "interface inheritance interface".
class Point { x: number; y: number; constructor(x: number, y: number) { this.x = x; this.y = y; } } interface PointInstanceType { x: number; y: number; } // Equivalent to interface point3d extensions pointinstancetype interface Point3d extends Point { z: number; } let point3d: Point3d = {x: 1, y: 2, z: 3};
Except that constructors are not included, static properties or static methods are not included (of course, the type of an instance should not include constructors, static properties or static methods)
That is, the type quality created by the declaration class contains the instance properties and instance methods
class Point { /** Static properties, coordinate system origin */ static origin = new Point(0, 0); /** Static method, calculate the distance from the origin */ static distanceToOrigin(p: Point) { return Math.sqrt(p.x * p.x + p.y * p.y); } /** Instance property, value of x axis */ x: number; /** Instance property, value of y-axis */ y: number; /** Constructor */ constructor(x: number, y: number) { this.x = x; this.y = y; } /** Instance method, print this point */ printPoint() { console.log(this.x, this.y); } } interface PointInstanceType { x: number; y: number; printPoint(): void; } let p1: Point; let p2: PointInstanceType;
Generics
Generic type refers to a feature that does not specify a specific type in advance when defining a function, interface or class, but specifies a type when using it.
Simple example
function createArray<T>(length: number, value: T): Array<T> { let result: T[] = []; for (let i = 0; i < length; i++) { result[i] = value; } return result; } // You can choose to specify or not, and the type inference will be calculated automatically createArray<string>(3, 'x'); // ['x', 'x', 'x'] createArray(3, 'x'); // ['x', 'x', 'x']
Multiple type parameters
function swap<T, U>(tuple: [T, U]): [U, T] { return [tuple[1], tuple[0]]; } // Tuples used to exchange input swap([7, 'seven']); // ['seven', 7]
Generic constraints
We use extensions to constrain that generic T must conform to the shape of interface Lengthwise, that is, it must contain the length attribute.
At this time, if the arg passed in does not contain length when calling loggingIdentity, an error will be reported at the compilation stage:
interface Lengthwise { length: number; } function loggingIdentity<T extends Lengthwise>(arg: T): T { console.log(arg.length); return arg; } loggingIdentity(7); // index.ts(10,17): error TS2345: Argument of type '7' is not assignable to parameter of type 'Lengthwise'.
Multiple type parameters can also be constrained to each other. T is required to inherit u, which ensures that fields that do not exist in T will not appear on U
function copyFields<T extends U, U>(target: T, source: U): T { for (let id in source) { target[id] = (<T>source)[id]; } return target; } let x = { a: 1, b: 2, c: 3, d: 4 }; copyFields(x, { b: 10, d: 20 });
generic interface
interface CreateArrayFunc<T> { (length: number, value: T): Array<T>; } let createArray: CreateArrayFunc<any>; createArray = function<T>(length: number, value: T): Array<T> { let result: T[] = []; for (let i = 0; i < length; i++) { result[i] = value; } return result; } createArray(3, 'x'); // ['x', 'x', 'x']
Generic class
class GenericNumber<T> { zeroValue: T; add: (x: T, y: T) => T; } let myGenericNumber = new GenericNumber<number>(); myGenericNumber.zeroValue = 0; myGenericNumber.add = function(x, y) { return x + y; };
Default type of generic parameter
We can specify the default type for type parameters in generics. When using generics, the default type will work when the type parameter is not specified directly in the code and cannot be inferred from the actual value parameter
function createArray<T = string>(length: number, value: T): Array<T> { let result: T[] = []; for (let i = 0; i < length; i++) { result[i] = value; } return result; }
Declaration merge
If two functions, interfaces, or classes with the same name are defined, they are merged into one type
Merging of functions
// Overload defines multiple function types function reverse(x: number): number; function reverse(x: string): string; function reverse(x: number | string): number | string { if (typeof x === 'number') { return Number(x.toString().split('').reverse().join('')); } else if (typeof x === 'string') { return x.split('').reverse().join(''); } }
Merging of interfaces
The properties in the interface will be simply merged into one interface when merging
interface Alarm { price: number; weight: number; }
The type of the merged property must be unique
interface Alarm { price: number; } interface Alarm { price: string; // If the type is inconsistent, an error will be reported weight: number; } // index.ts(5,3): error TS2403: Subsequent variable declarations must have the same type. Variable 'price' must be of type 'number', but here has type 'string'.
The merging of methods in the interface is the same as that of functions:
interface Alarm { price: number; alert(s: string): string; } interface Alarm { weight: number; alert(s: string, n: number): string; }
amount to
interface Alarm { price: number; weight: number; alert(s: string): string; alert(s: string, n: number): string; }
Merge of classes
interface Alarm { price: number; weight: number; alert(s: string): string; alert(s: string, n: number): string; }
engineering
Code check
In January 2019, TypeScirpt officially decided to fully adopt ESLint as a code inspection tool, and created a new project TypeScript ESLint, which provides the parser @ TypeScript ESLint / parser of TypeScript files and related configuration options @ TypeScript ESLint / ESLint plugin.
What is code checking
Code checking is mainly used to find code errors and unify code style.
In JavaScript projects, we generally use ESLint for code checking. It greatly enriches the scope of application through the plug-in feature. After matching TypeScript ESLint, it can even be used to check TypeScript code
Why do I need code checking
After compiling with tsc and checking with eslint respectively, the error message is as follows
var myName = 'Tom'; // eslint error message: // Unexpected var, use let or const instead.eslint(no-var) console.log(`My name is ${myNane}`); // tsc error message: // Cannot find name 'myNane'. Did you mean 'myName'? // eslint error message: // 'myNane' is not defined.eslint(no-undef) console.log(`My name is ${myName.toStrng()}`); // tsc error message: // Property 'toStrng' does not exist on type 'string'. Did you mean 'toString'?
- There are more advanced syntax let and const in ES6. At this time, it can be checked through eslint, suggesting that we should use let or const instead of var
- eslint cannot identify which methods exist for myName
- eslint can find some errors that tsc will not care about and check out some potential problems, so code checking is still very important.
Using ESLint in TypeScript
Install ESLint in the project
npm install --save-dev eslint
ESLint uses Espree for syntax parsing by default and cannot recognize some syntax of typescript, so we need to install @ typescript ESLint / parser instead of the default parser. Don't forget to install typescript at the same time
npm install --save-dev typescript @typescript-eslint/parser
@Typescript eslint / eslint plugin, as a supplement to the default eslint rules, provides some additional rules applicable to ts syntax
npm install --save-dev @typescript-eslint/eslint-plugin
create profile
ESLint needs a configuration file to decide which rules to check. The name of the configuration file is usually eslintrc.js or eslintrc.json
When running ESLint to check a file, it will first try to read the configuration file in the directory of the file, and then look up one level at a time to merge the found configuration as the configuration of the currently checked file
Create one under the root directory of the project eslintrc.js, as follows:
module.exports = { parser: '@typescript-eslint/parser', plugins: ['@typescript-eslint'], rules: { // var is prohibited 'no-var': "error", // interface is preferred over type '@typescript-eslint/consistent-type-definitions': [ "error", "interface" ] } }
In the above configuration, we specify two rules. No VaR is the native rule of ESLint and @ typescript ESLint / consistent type definitions is the new rule of @ typescript ESLint / ESLint plugin.
One of off, warn or error, which indicates shutdown, warning and error
The meanings of shutdown, warning and error reporting are as follows: Close: disable this rule Warning: error message is output during code check, but it will not affect exit code Error reporting: when an error is found, it will not only output error information, but also exit code Will be set to 1 (general) exit code (if it is not 0, there is an error in execution)
Check a ts file
Create a new file index ts
var myName = 'Tom'; type Foo = {};
Execution/ node_modules/.bin/eslint index.ts
Get error report:
/path/to/index.ts 1:1 error Unexpected var, use let or const instead no-var 2:6 error Use an `interface` instead of a `type` @typescript-eslint/consistent-type-definitions ✖ 2 problems (2 errors, 0 warnings) 1 error and 0 warnings potentially fixable with the `--fix` option.
It's inconvenient to execute such a long script every time. We can Add a script to JSON to create an npm script to simplify this step
{ "scripts": { "eslint": "eslint index.ts" } }
Just execute npm run eslint
Check the ts file of the whole project
The project source file is usually placed in the src directory, so package Instead, the eslint script in JSON checks a directory. Because eslint does not check by default TS suffix file, so you need to add the parameter -- ext ts
{ "scripts": { "eslint": "eslint src --ext .ts" } }
At this point, execute npm run eslint to check all the files in the src directory Files with ts suffix
Integrating ESLint check in VSCode
Plug in name: ESLint
The ESLint plug-in in VSCode does not check by default For ts suffix, you need to add the following configuration in "file = > Preferences = > Settings = > workspace" (you can also create a configuration file. vscode/settings.json in the project root directory):
{ "eslint.validate": [ "javascript", "javascriptreact", "typescript" ], "typescript.tsdk": "node_modules/typescript/lib" }
. ts file, move the mouse to the red prompt to see such error information
In addition, automatically repair when saving and modify the configuration file
{ "editor.codeActionsOnSave": { "source.fixAll": true, "source.fixAll.eslint": true }, "eslint.validate": [ "javascript", "javascriptreact", "typescript" ], "typescript.tsdk": "node_modules/typescript/lib" }
Fix formatting errors using Prettier
ESLint includes some code format checks, such as spaces, semicolons, etc. But there is a more advanced tool in the front-end community that can be used to format code, that is Prettier
Prettier focuses on code formatting, reorganizes the code format through syntax analysis, and keeps everyone's code in the same style
Installing Prettier
npm install --save-dev prettier
Create a prettier config. JS file, which contains the configuration items of prettier. Prettier has few configuration items. Here I recommend a configuration rule
// prettier.config.js or .prettierrc.js module.exports = { // A line of up to 100 characters printWidth: 100, // Indent with 4 spaces tabWidth: 4, // Use spaces instead of indents useTabs: false, // A semicolon is required at the end of the line semi: true, // single quotes singleQuote: true, // The key of the object is quoted only when necessary quoteProps: 'as-needed', // jsx does not use single quotes, but double quotes jsxSingleQuote: false, // Comma is not required at the end trailingComma: 'none', // Spaces are required at the beginning and end of braces bracketSpacing: true, // The inverse angle brackets of jsx tags need to wrap jsxBracketSameLine: false, // When the arrow function has only one parameter, parentheses are also required arrowParens: 'always', // The format range of each file is the whole content of the file rangeStart: 0, rangeEnd: Infinity, // You don't need to write @ prettier at the beginning of the file requirePragma: false, // There is no need to automatically insert @ prettier at the beginning of the file insertPragma: false, // Use default line break criteria proseWrap: 'preserve', // Determine whether html should be folded or not according to the display style htmlWhitespaceSensitivity: 'css', // Line breaks use lf endOfLine: 'lf' };
Use the ESLint configuration of AlloyTeam
There are too many native ESLint rules and @ TypeScript ESLint / ESLint plugin rules, and some native rules are not well supported in TypeScript and need to be disabled
install
npm install --save-dev eslint typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-config-alloy
Yes eslintrc.js
module.exports = { extends: [ 'alloy', 'alloy/typescript', ], env: { // Your environment variables (including multiple predefined global variables) // Your environments (which contains several predefined global variables) // // browser: true, // node: true, // mocha: true, // jest: true, // jquery: true }, globals: { // Your global variable (set to false to indicate that it is not allowed to be reassigned) // Your global variables (setting to false means it's not allowed to be reassigned) // // myGlobal: false }, rules: { // Customize your rules // Customize your rules } };
Using ESLint to check tsx files
Install eslint plugin react:
npm install --save-dev eslint-plugin-react
package. Scripts in JSON Eslint add tsx suffix
{ "scripts": { "eslint": "eslint src --ext .ts,.tsx" } }
New typescriptreact check in VSCode configuration
{ "eslint.validate": [ "typescriptreact" ], }