Author: Become a good little white
Making: making
Hobby: Americano More Ice!
An inner volume note about Typescript
- Typescript
- Introduction to the
- The installation
- Write your first demo
- basis
- Primitive data type
- Boolean value
- The numerical
- string
- A null value
- Any value
- Type inference
- The joint type
- Object type – Interface
- An array type
- Function types
- Type Assertion
- Type assertion purpose
- Restrictions on type assertions
- Double assertion
- Type assertion vs type conversion
- Type assertion vs type declaration
- Type assertion vs generics
- Declaration file
- New syntactic index
- What is a declaration statement
- What is a declaration file
- Third Party Declaration Document
- Written declaration document
- The global variable
- declare var
- declare function
- declare class
- declare enum
- declare namespace
- Interface and type
- Preventing naming conflicts
- A statement to merge
- NPM package
- export
- Mix DECLARE and export
- export namespace
- export default
- export =
- The global variable
- UMD library
- export as namespace
- Expand global variables directly
- Extend global variables in NPM packages or UMD libraries
- declare global
- Module plug-ins
- Declare dependencies in files
- Three slash instruction
- Write a global variable declaration file
- A declaration file that depends on a global variable
- Split declaration file
- Three slash instruction
- Automatically generate declaration files
- Release statement file
- Built-in objects
- ECMAScript built-in object
- DOM and BOM built-in objects
- The TypeScript core library definition file
- Written in TypeScript Node. Js
- Primitive data type
- The advanced
- Type the alias
- String literal type
- tuples
- The enumeration
- Manual assignment
- Constant term and computed term
- Constant enumeration
- External enumeration (Ambient Enums)
- class
- The concept of class
- ES6 class usage
- Properties and methods
- Class inheritance
- accessor
- A static method
- ES7 class usage
- Instance attributes
- Static attributes
- TypeScript class usage
- Public, private and protected
- Parameter properties
- readonly
- An abstract class
- The type of the class
- Classes and interfaces
- Class implementation interface
- Interface Inheritance interface
- Interface inheritance class
- Generics
- Simple example
- Multiple type parameters
- Generic constraint
- A generic interface
- A generic class
- The default type of a generic parameter
- A statement to merge
- Combination of functions
- Merging interfaces
- Such merger
- engineering
- Code review
- What is code review
- Why code review
- Use ESLint in TypeScript
- Install ESLint in the project
- Creating a Configuration File
- Check a TS file
- Review the TS files for the entire project
- Integrate ESLint checking with VSCode
- Use Prettier to fix formatting errors
- ESLint configuration using AlloyTeam
- Use ESLint to check TSX files
- Code review
Introduction to the
TypeScript is a superset of JavaScript types that can be compiled into pure JavaScript. The compiled JavaScript can run on any browser. TypeScript compilation tools can run on any server and on any system. TypeScript is open source.
The installation
npm install -g typescript
There is a TSC global command when the installation is complete
Write your first demo
// hello.ts
function sayHello(person: string) {
return 'Hello, ' + person;
}
let user = 'Tom';
console.log(sayHello(user));
Copy the code
Execute TSC hello.ts to generate hello.js
function sayHello(person) {
return 'Hello, ' + person;
}
var user = 'Tom';
console.log(sayHello(user));
Copy the code
Compare the differences:
ts
Insert parameters will have parameter types,ts
Only static checks are performed, and if any errors are found, an error is reported at compile timelet
是ES6
The keyword, andvar
Similarly, used to define a local variable
basis
Primitive data type
JavaScript comes in two types: Primitive data types and Object types.
Primitive data types include: Boolean, numeric, string, NULL, undefined, and the new type Symbol in ES6.
Boolean value
// Boolean is a basic type in JavaScript, and Boolean is a constructor in JavaScript
let isDone: boolean = false;
// Returns a Boolean object
let createdByNewBoolean: Boolean = new Boolean(1);
Return a Boolean type
let createdByBoolean: boolean = Boolean(1);
Copy the code
The numerical
// Where 0b1010 and 0o744 are binary and octal representations in ES6, which are compiled to 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;
Copy the code
string
// 'is used to define template strings, and ${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`;
Copy the code
A null value
// Indicates that no value is returned
function alertName() :void {
alert('My name is Tom');
}
// It is useless to declare a void variable because you can only assign it to undefined and null
let unusable: void = undefined;
Copy the code
/ / Null, and Undefined
let u: undefined = undefined;
let n: null = null;
// Undefined and null are subtypes of all types
// variables of type undefined can be assigned to variables of type number
let num: number = undefined;
/ / or
let u: undefined;
let num: number = u;
// void does not work
let u: void;
let num: number = u;
// Type 'void' is not assignable to type 'number'.
Copy the code
Any value
An arbitrary value (Any) is used to indicate that assignments of Any type are allowed
After declaring a variable as an arbitrary value, any operation on it returns the type of an arbitrary value
/ / usage
let myFavoriteNumber: any = 'seven';
myFavoriteNumber = 7;
// Access any attributes
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');
Copy the code
A variable is recognized as any value type if its type is not specified when it is declared
// let something: any;
let something;
something = 'seven';
something = 7;
something.setName('Tom');
Copy the code
Type inference
TypeScript extrapolates a type when no type is explicitly specified. This is called type inference
// No type is specified, but a string is assigned
// Compile error
let myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
// There is no assignment at the time of the definition, and any subsequent assignment or not will be inferred to be of type any
// Not checked at all
let myFavoriteNumber;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
Copy the code
The joint type
Union Types indicate that the value can be one of many Types
/ / joint types using | separated for each type
// Yes, the myFavoriteNumber type is allowed to be string or number, but not other types
let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
/ / an error
let myFavoriteNumber: string | number;
myFavoriteNumber = true;
Copy the code
When TypeScript doesn’t know what type a variable of a union type is, we can only access properties or methods that are common to all types of the union type
// Length is not a common attribute of string and number, so an error is reported
function getLength(something: string | number) :number {
return something.length;
}
/ / index. Ts (2, 2) : error TS2339: Property 'length' does not exist on the type 'string | number'.
// Property 'length' does not exist on type 'number'.
Copy the code
It is ok to access the common properties of string and number
function getString(something: string | number) :string {
return something.toString();
}
Copy the code
When a variable of a union type is assigned, a type is inferred according to the rules of type inference
let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven';
// Infer to string
console.log(myFavoriteNumber.length); / / 5
// Deduce the number
myFavoriteNumber = 7;
console.log(myFavoriteNumber.length); // Error when compiling
Copy the code
Object type – Interface
In TypeScript, we use Interfaces to define the types of objects.
- What is an interface
Interfaces are an important concept in object-oriented languages. They are an abstraction of behavior, and that behavior needs to be implemented by classes.
Interfaces in TypeScript are a very flexible concept. In addition to abstracting some of the behavior of a class, interfaces are often 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 the same as the interface Person
// That is, the number and type of attributes should be the same
let tom: Person = {
name: 'Tom'.age: 25
};
Copy the code
- Optional attribute
Instead of matching a shape exactly, use optional attributes:
interface Person {
name: string; age? :number;
}
// Optional attribute age, free to exist or not exist
let tom: Person = {
name: 'Tom'
};
Copy the code
- Any attribute
An interface can have arbitrary attributes, which can be used as follows
interface Person {
name: string; age? :number;
[propName: string] :any;
}
let tom: Person = {
name: 'Tom'.gender: 'male'
};
Copy the code
Note: Once an arbitrary attribute is defined, the type of both the determined attribute and the optional attribute must be a subset of its type:
interface Person {
name: string; age? :number;
[propName: string] :string;
}
// Age is not string
let tom: Person = {
name: 'Tom'.age: 25.gender: 'male'
};
// Use the 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'
};
Copy the code
- Read-only property
Sometimes we want fields in an object to be assigned only at creation time, so we can use readonly to define read-only properties
interface Person {
readonly id: number;
name: string; age? :number;
[propName: string] :any;
}
let tom: Person = {
id: 89757.name: 'Tom'.gender: 'male'
};
// An error was reported because the property is read-only
tom.id = 9527;
Copy the code
Note that the read-only constraint exists the first time an object is assigned, not the first time a read-only property is assigned
interface Person {
readonly id: number;
name: string; age? :number;
[propName: string] :any;
}
// 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;
Copy the code
An array type
In TypeScript, array types are defined in several ways
Such as:
let fibonacci: number[] = [1.1.2.3.5];
Copy the code
No other types are allowed in an array item
let fibonacci: number[] = [1.'1'.2.3.5];
// Type 'string' is not assignable to type 'number'.
Copy the code
The parameters of some methods of arrays are also limited by the types that are 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'.
Copy the code
- Array Generic
Array
represents the Array
let fibonacci: Array<number> = [1.1.2.3.5];
Copy the code
- Interface representation array
// NumberArray indicates that the value type must be numeric if the index type is numeric
interface NumberArray {
[index: number] :number;
}
let fibonacci: NumberArray = [1.1.2.3.5];
Copy the code
- Class Array (array-like Object)
The array-like Object class is not an Array type, such as Arguments
function sum() {
let args: number[] = arguments;
}
// Instead of using an array, use an interface
// The value must be of a type other than a number
// It has two attributes: length and callee
function sum() {
let args: {
[index: number] :number;
length: number;
callee: Function;
} = arguments;
}
Copy the code
In fact, common class arrays have their own interface definitions, such as IArguments, NodeList, HTMLCollection, etc
function sum() {
let args: IArguments = arguments;
}
// IArguments are TypeScript defined types
interface IArguments {
[index: number] :any;
length: number;
callee: Function;
}
Copy the code
- Application of any to arrays
A common practice is to use any to indicate that any type is allowed in an array
let list: any[] = ['xiaobiao'.25, { website: 'http://xcatliu.com' }];
Copy the code
Function types
There are two common ways to define functions in JavaScript
- Function Declaration
- Function Expression
// Function Declaration
function sum(x, y) {
return x + y;
}
// Function Expression
let mySum = function (x, y) {
return x + y;
};
Copy the code
- Function declaration
Ts is a little different in that it uses constraints
function sum(x: number, y: number) :number {
return x + y;
}
// Entering extra (or less than required) parameters is not allowed
/ / an error
sum(1.2.3);
sum(1);
/ / right
sum(1.2)
Copy the code
- Functional expression
In TypeScript type definitions, => is used to represent function definitions, with input types enclosed in parentheses on the left and output types on the right.
In ES6, the => is called the arrow function and is widely used
let mySum = function (x: number, y: number) :number {
return x + y;
};
// The above code only defines the anonymous function to the right of the equals sign, while the mySum to the left of the equals sign is inferred from the type inference of the assignment operation
// Add the type to mySum manually
let mySum: (x: number, y: number) = > number = function (x: number, y: number) :number {
return x + y;
};
Copy the code
- Define the shape of a function with an interface
interface SearchFunc {
(source: string.subString: string) :boolean;
}
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
returnsource.search(subString) ! = = -1;
}
Copy the code
- Optional parameters
function buildName(firstName: string, lastName? :string) {
if (lastName) {
return firstName + ' ' + lastName;
} else {
returnfirstName; }}let tomcat = buildName('Tom'.'Cat');
let tom = buildName('Tom');
Copy the code
Optional arguments are no longer allowed to be followed by required arguments
function buildName(firstName? :string, lastName: string) {
if (firstName) {
return firstName + ' ' + lastName;
} else {
returnlastName; }}let tomcat = buildName('Tom'.'Cat');
let tom = buildName(undefined.'Tom');
// index.ts(1,40): error TS1016: A required parameter cannot follow an optional parameter
Copy the code
- Parameter Default Value
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');
Copy the code
No longer restricted 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');
Copy the code
- The remaining parameters
function push(array: any[], ...items: any[]) {
items.forEach(function(item) {
array.push(item);
});
}
let a = [];
push(a, 1.2.3);
Copy the code
- overloading
Overloading allows a function to take different numbers or types of arguments and behave differently.
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(' '); }}Copy the code
Type Assertion
Type assertions can be used to manually specify the type of a value
Grammar:
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 that (animal as Fish).swim() this code hides the possibility that animal is Cat
// The TypeScript compiler trusts our assertion so there is no compilation error 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`
Copy the code
- Assert a parent class as a more concrete subclass
Interface types can only be determined using type assertions to determine if code is AirError class type 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') {
// The following is a more appropriate method
// it is more appropriate to use instanceof, since ApiError is a JavaScript class and instanceof can be used to determine if an error is an instanceof it
// if (error instanceof ApiError) {
return true;
}
return false;
}
Copy the code
- Assert any type as any
It most likely hides a true type error, so don’t use as any unless you’re absolutely sure
Syntax: (window as any).foo = 1;
- Assert any as a concrete type
It is best to assert the return value of a call to an exact type to facilitate subsequent operations (increased 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();
Copy the code
Restrictions on type assertions
- A union type can be asserted as one of these types
- A parent class can be asserted as a subclass
- Any type can be asserted to be any
- Any can be asserted to any type
- In order for A to be asserted as B, either A is compatible with B or B is compatible with A
When Animal is compatible with Cat, they can make type assertions to 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);
}
Copy the code
Double assertion
Never use double assertion unless you absolutely have to
Type assertion vs type conversion
A type assertion is not a conversion and does not really affect the type of a variable
To cast, you need to call the cast method directly
function toBoolean(something: any) :boolean {
return Boolean(something);
}
toBoolean(1);
// Return true
Copy the code
Type assertion vs type declaration
interface Animal {
name: string;
}
interface Cat {
name: string;
run(): void;
}
const animal: Animal = {
name: 'tom'
};
// Since Animal is compatible with Cat, we can assign the Animal assertion to Cat to Tom
let tom = animal as Cat;
// let tom: Cat = animal; An error
// Animal can be considered as a parent of Cat. Of course, you cannot assign an instance of a parent to a variable of type subclass.
Copy the code
Animal Cat = Cat animal Cat = Cat animal Animal is assigned to Tom only if Cat is compatible with Animal
In summary, type declarations are more stringent and elegant than type assertions
Type assertion vs generics
Before the change
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();
Copy the code
The modified
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();
Copy the code
By adding a generic < T > to the getCacheData function, we can more formally implement the constraints on the getCacheData return value. This also removes any from the code, which is the best solution.
Declaration file
When using a third-party library, we need to reference its declaration file to get the corresponding code completion, interface prompts and other functions
New syntactic index
`declare var`Declare global variables`declare function`Declare global methods`declare class`Declaring a global class`declare enum`Declare a global enumeration type`declare namespace`Declare a global object with child attributes`interface`And type declare the global type`export`Export variables`export namespace`Export objects (with child attributes)`export default`On the ES6, it is exported by default`export =`Commonjs export module`export as namespace`The UMD library declares global variables`declare global`Extend global variable`declare module`Extension module`/// <reference />`Three slash instructionCopy the code
What is a declaration statement
If we want to use the third-party library jQuery, a common way to do this is to import jQuery in HTML with a script tag, and then use the global variable $or jQuery.
// declare var does not really define a variable, just the type of the global variable jQuery
// Will only be used for compile-time checks and will be removed from the compilation result
declare var jQuery: (selector: string) = > any;
jQuery('#foo');
Copy the code
JQuery (‘#foo’);
What is a declaration file
Usually we put declarations 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');
Copy the code
Declaration files must have a.d.ts suffix
In general, TS parses all *. Ts files in a project, including those ending in.d.ts. So when we put jquery.d.ts in the project, all the other *.ts files will get the jQuery type definition
The/path/to/project ├ ─ ─ the SRC | ├ ─ ─ but ts | └ ─ ─ jQuery. Which s └ ─ ─ tsconfig. JsonCopy the code
If you still can’t parse, check the files, include, and exclude configurations in tsconfig.json to make sure they include jquery.d. ts files
Third Party Declaration Document
It is recommended that you use @Types to manage third-party library declaration files uniformly.
The use of @types is simple, simply install the corresponding declaration module with NPM, e.g
npm install @types/jquery --save-dev
Written declaration document
The global variable
When using declarations of global variables, no configuration is required if installed as NPM install@types/XXX –save-dev. If you want to store the declaration file 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 directory).
Global variable declaration files have the following syntax:
`declare var`Declare global variables`declare function`Declare global methods`declare class`Declaring a global class`declare enum`Declare a global enumeration type`declare namespace`Declare a global object with child attributes` interface and type `Declaring global typesCopy the code
declare var
In general, global variables are non-modifiers, so in most cases you should use const instead of var or let.
// src/jQuery.d.ts
declare const jQuery: (selector: string) = > any;
// jQuery('#foo');
// Use the jQuery type defined by Declare const to prohibit modifying 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 declarations. Do not define specific implementations in declarations
// declare const jQuery = function(selector) {
// return document.querySelector(selector);
// };
// ERROR: An implementation cannot be declared in ambient contexts.
Copy the code
declare function
The type used to define a global function. JQuery is a function, so you can use function as well
Example:
// src/jQuery.d.ts
declare function jQuery(selector: string) :any;
// src/index.ts
jQuery('#foo');
Copy the code
Function overloading is also supported in declarations of function types
// 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! ');
});
Copy the code
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');
Copy the code
Declare Class statements can also only be used to define types (as can DECLARE var), not concrete implementations, such as defining concrete implementations of the sayHi method
Examples of errors:
// src/Animal.d.ts
declare class Animal {
name: string;
constructor(name: string);
sayHi() {
return `My name is The ${this.name}`;
};
// ERROR: An implementation cannot be declared in ambient contexts.
}
Copy the code
declare enum
Enumeration types defined using declare enum 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]
Copy the code
declare namespace
Namespace is a key word created by TS in the early days to solve the modularity problem
JQuery is a global variable. It is an object that provides a jquery. ajax method to call
Inside the Declare Namespace, we declare functions directly using function Ajax instead of using Declare Function Ajax. Similarly, we can use const, class, enum, etc
// 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);
Copy the code
Interface and type
In a type declaration file, we can declare a global interface or type directly using interface or type
// src/jQuery.d.ts
interfaceAjaxSettings { 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);
Copy the code
Preventing naming conflicts
Interfaces or types exposed in the outermost layer are used as global types throughout the project, and we should minimize the number of global variables or global types. Therefore, it is best to put them under namespace
A statement to 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');
Copy the code
NPM package
NPM package declaration file has the following syntax:
exportExport variablesexportNamespace Exports objects with child attributesexportDefault ES6 Exports data by defaultexport= CommonJS Export moduleCopy the code
export
The NPM package declaration file is quite different from the global variable declaration file. In the declaration file of the NPM package, using DECLARE no longer declares a global variable, but only a local variable in the current file. These type declarations are applied only after export is exported 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;
}
Copy the code
The corresponding import and use modules should look like this:
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'}};Copy the code
Mix DECLARE and export
Declare multiple variables with DECLARE and export at the end
// 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 };
Copy the code
Note: Interface does not require declare
export namespace
The export namespace command is used to export an object with child attributes
// types/foo/index.d.ts
export namespace foo {
const name: string;
namespace bar {
function baz() :string; }}Copy the code
// src/index.ts
import { foo } from 'foo';
console.log(foo.name);
foo.bar.baz();
Copy the code
export default
In the ES6 module system, export default can be used to export a default value, which can be imported by using import foo from ‘foo’ instead of import {foo} from ‘foo’
Only function, class, and interface can be exported by default. Other variables need to be defined before being exported by default
// types/foo/index.d.ts
export default function foo() :string;
Copy the code
// src/index.ts
import foo from 'foo';
foo();
Copy the code
For other default exports, the export statement is typically placed at the top of the declaration file
export default Directions;
declare enum Directions {
Up,
Down,
Left,
Right
}
Copy the code
export =
In the CommonJS specification, we export a module in the following way
// Export as a whole
module.exports = foo;
// Single export
exports.bar = bar;
Copy the code
In TS, there are several ways to import such module exports. The first is const… = require
// Whole import
const foo = require('foo');
// Single import
const bar = require('foo').bar;
Copy the code
The second way is to import… From, note that for the overall export, import * as is required
// Whole import
import * as foo from 'foo';
// Single import
import { bar } from 'foo';
Copy the code
The third way is to import… Require, which is also the official ts recommendation
// Whole import
import foo = require('foo');
// Single import
import bar = foo.bar;
Copy the code
For libraries that use the CommonJS specification, if you want to write a type declaration file for it, you need to use the syntax export =
// types/foo/index.d.ts
export = foo;
declare function foo() :string;
declare namespace foo {
const bar: number;
}
Copy the code
UMD library
export as namespace
Generally, when you use export as namespace (for declaring additional global variables), you can 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, as shown in the following 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;
}
Copy the code
Expand global variables directly
Some third-party libraries extend a global variable, but the type of the global variable is not updated, resulting in TS compilation errors. In this case, the type of the global variable needs to be extended. For example, extend String
interface String {
prependHello(): string;
}
'foo'.prependHello();
Copy the code
You can also use declare Namespace to add a type declaration to an existing namespace
// types/jquery-plugin/index.d.ts
declare namespace JQuery {
interface CustomOptions {
bar: string; }}interface JQueryStatic {
foo(options: JQuery.CustomOptions): string;
}
Copy the code
// src/index.ts
jQuery.foo({
bar: ' '
});
Copy the code
Extend global variables in NPM packages or UMD libraries
declare global
You can extend the types of global variables in the NPM package or in the UMD library declaration file
// types/foo/index.d.ts
declare global {
interface String {
prependHello(): string; }}// Note that even though 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 global variable declaration file
export {};
Copy the code
// src/index.ts
'bar'.prependHello();
Copy the code
Module plug-ins
Ts provides a syntax Declare Module that can be used to extend the type of an existing module
// types/moment-plugin/index.d.ts
import * as moment from 'moment';
declare module 'moment' {
export function foo() :moment.CalendarKey;
}
Copy the code
// src/index.ts
import * as moment from 'moment';
import 'moment-plugin';
moment.foo();
Copy the code
The Declare Module can also be used to declare multiple module types at once in a file
// types/foo-bar.d.ts
declare module 'foo' {
export interface Foo {
foo: string; }}declare module 'bar' {
export function bar() :string;
}
Copy the code
// src/index.ts
import { Foo } from 'foo';
import * as bar from 'bar';
let f: Foo;
bar.bar();
Copy the code
Declare dependencies in files
One declaration file sometimes relies on the types in another declaration file. For example, in the previous declare Module example, we imported moment into the declaration file and used moment.CalendarKey
// types/moment-plugin/index.d.ts
import * as moment from 'moment';
declare module 'moment' {
export function foo() :moment.CalendarKey;
}
Copy the code
Three slash instruction
Like an import in a declaration file, it can be used to import another declaration file. The difference with import is that we need to replace import with a triple slash directive if and only if:
- When we write a declaration file for a global variable
- When we need to rely on a global variable declaration file
Write a global variable declaration file
These scenarios sound like a mouthful, but they actually make sense — the import and export keywords are not allowed in declarations of global variables. Once present, it is treated as an NPM package or UMD library and is no longer a declaration file for global variables. Therefore, when writing a global variable declaration file, we must use the triple slash directive if we need to reference another library type
// types/jquery-plugin/index.d.ts
/// <reference types="jquery" />
declare function foo(options: JQuery.AjaxSettings) :string;
Copy the code
// src/index.ts
foo({});
Copy the code
The jquery. AjaxSettings type is used in the declaration file. The jquery. AjaxSettings type is used in the declaration file
Note that the triple slash directive must be placed at the top of the file, and only one or more lines of comments are allowed before the triple slash directive
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, we must use the triple slash directive because global variables cannot be imported through import
// types/node-plugin/index.d.ts
/// <reference types="node" />
export function foo(p: NodeJS.Process) :string;
Copy the code
// types/node-plugin/index.d.ts
/// <reference types="node" />
export function foo(p: NodeJS.Process) :string;
Copy the code
Split declaration file
When our global variable declaration file is too large, we can improve the maintainability of our code by splitting it into multiple files and then importing them one by one in an entry file. JQuery’s declaration file, for example, does 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;
Copy the code
Automatically generate declaration files
TSC xx. Ts -d or TSC xx. Ts –declaration TSC xx
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: Add the declaration option to tsconfig.json. Tsconfig. json is used as an example
{
"compilerOptions": {
"module": "commonjs"."outDir": "lib"."declaration": true}}Copy the code
Release statement file
Once we have written the declaration file for a library, the next step is to publish it.
There are two options:
- Put the declaration file with the source code
- Publish the declaration file to
@types
下
Built-in objects
There are many built-in objects in JavaScript that can be treated directly as defined types in TypeScript.
Built-in objects are objects that exist in the Global scope according to the standard. Standards here refer to ECMAScript and standards in other environments such as DOM
ECMAScript built-in object
The ECMAScript standard provides built-in objects such as Boolean, Error, Date, RegExp, etc.
let b: Boolean = new Boolean(1);
let e: Error = new Error('Error occurred');
let d: Date = new Date(a);let r: RegExp = /[a-z]/;
Copy the code
More built-in object core library definitions
DOM and BOM built-in objects
DOM and BOM provide built-in objects such as Document, HTMLElement, Event, and NodeList.
/ / the commonly used
let body: HTMLElement = document.body;
let allDiv: NodeList = document.querySelectorAll('div');
document.addEventListener('click'.function(e: MouseEvent) {
// Do something
});
Copy the code
Core Library Definition
The TypeScript core library definition file
The TypeScript core library definition files define the types needed by all browser environments and are preconfigured in TypeScript.
Written in TypeScript Node. Js
Node.js is not part of the built-in object. If you want to write Node.js in TypeScript, you need to import a third-party declaration file: NPM install @types/ Node –save-dev
The advanced
Type the alias
Type aliases are often used to combine types
type Name = string;
type NameResolver = () = > string;
type NameOrResolver = Name | NameResolver;
function getName(n: NameOrResolver) :Name {
if (typeof n === 'string') {
return n;
} else {
returnn(); }}Copy the code
String literal type
The string literal type is used to constrain the value to 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'); // Error: event cannot be 'dblclick'
// index.ts(7,47): error TS2345: Argument of type '"dblclick"' is not assignable to parameter of type 'EventNames'.
Copy the code
Note that both type aliases and string literal types are defined using type.
tuples
Arrays merge objects of the same type, while tuples merge objects of different types.
Tuples originated in functional programming languages such as F#, where tuples are frequently used
let tom: [string.number];
tom[0] = 'Tom';
tom[1] = 25;
tom[0].slice(1);
tom[1].toFixed(2);
Copy the code
Out-of-bounds arrays: 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'.
Copy the code
The enumeration
The enumeration (Enum) type applies to scenarios where the value is limited within a certain range, for example, there are only seven days in a week, and the color is limited to red, green and blue
Enumerators are assigned an increasing number starting from 0, and the enumeration value is also mapped backwards to the enumeration 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
Copy the code
Manual assignment
TypeScript doesn’t notice if an unmanually assigned enumeration item duplicates the manually assigned one
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
Copy the code
Manually assigned enumerations may not be numbers, in which case type assertions are needed to make TSC ignore type checking (the compiled JS is still available) :
enum Days {Sun = 7, Mon, Tue, Wed, Thu, Fri, Sat = <any>"S"};
Copy the code
Manually assigned enumerations can also be decimal or negative, with subsequent unmanually assigned enumerations still increasing by 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
Copy the code
Constant term and computed term
There are two types of enumeration items: constant (constant member) and computed (computed member)
// Correct example
enum Color {Red, Green, Blue = "blue".length};
// Error example
// If the computed item is immediately followed by an item that is not 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.
Copy the code
Enumerators are treated as constants if:
There is no initialization function and the previous enumerator is a constant. In this case, the current enumerator’s value is the value of the previous enumerator plus one. The first enumeration element is an exception. If it has no initialization method, its initial value is 0.
Enumerator members are initialized with constant enumeration expressions. Constant enumerated expressions are a subset of TypeScript expressions that can be evaluated at compile time. An expression is a constant enumerated expression when it satisfies one of the following conditions:
Numeric literal
Reference to a previously defined constant enumerator (which can be defined in a different enumeration type). If the member is defined in the same enumeration type, it can be referenced by an unqualified name
A bracketed constant enumeration expression
The +, -, ~ unary operators are applied to constant enumeration expressions
The +, -, *, /, %, < <, > >, > > >, &, |, ^ binary operators, constant enumeration expression as its an operation object. If the constant enumeration expression evaluates to NaN or Infinity, an error is reported at compile time
Enumerators in all other cases are treated as values that need to be computed.
Constant enumeration
const enum Directions {
Up,
Down,
Left,
Right
}
let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
Copy the code
Constant enumerations differ from regular enumerations in that they are removed at compile time and cannot contain computed members.
If a calculated member is included, an error is reported at compile time:
const enum Color {Red, Green, Blue = "blue".length};
// index.ts(1,38): error TS2474: In 'const' enum declarations member initializer must be constant expression.
Copy the code
External enumeration (Ambient Enums)
declare enum Directions {
Up,
Down,
Left,
Right
}
let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
Copy the code
It is also possible to use both declare and const:
declare const enum Directions {
Up,
Down,
Left,
Right
}
let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
Copy the code
class
The concept of class
- Class: defines the abstract characteristics of a thing, including its properties and methods. - Object: an instance of a Class, generated through new. - Three main features of OOP: Encapsulation, inheritance, and Polymorphism - Encapsulation: Hide the details of manipulation of data, exposing only the external interface. External callers don't need (and can't) know the details, so they can access the object through the interface provided externally, and at the same time, it also ensures that the external can't arbitrarily change the data inside the object. Subclasses inherit from their superclass. As well as having all the characteristics of their superclass, subclasses are also more specific: Polymorphism: the result of inheritance is that related different classes can respond differently to the same method. For example, Cat and Dog both inherit from Animal, but each implements its own eat method. For a particular instance, we can call the eat method without knowing whether it's Cat or Dog, and the program will automatically figure out how to perform the eat-accessors: Modifiers are keywords that qualify the nature of a member or type. For example, public stands for a public property or method-abstract Class: an Abstract Class is a base Class that other classes inherit, and an Abstract Class is not allowed to be instantiated. Abstract methods in an abstract class must be implemented in subclasses - Interfaces: properties or methods that are common between classes and can be abstracted into an interface. An interface can be implemented by a class. A class can only inherit from another class, but can implement multiple interfacesCopy the code
ES6 class usage
Properties and methods
Use class to define classes and constructor to define constructors.
The constructor is automatically called when a new instance is generated from new
class Animal {
public name;
constructor(name) {
this.name = name;
}
sayHi() {
return `My name is The ${this.name}`; }}let a = new Animal('Jack');
console.log(a.sayHi()); // My name is Jack
Copy the code
Class inheritance
The extends keyword is used for inheritance, and the super keyword is used in subclasses to call the constructors and methods of the parent class
class Cat extends Animal {
constructor(name) {
super(name); // Call parent class constructor(name)
console.log(this.name);
}
sayHi() {
return 'Meow, ' + super.sayHi(); SayHi ()}}let c = new Cat('Tom'); // Tom
console.log(c.sayHi()); // Meow, My name is Tom
Copy the code
accessor
Use getters and setters to change the assignment and read behavior of properties
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
Copy the code
A static method
Methods decorated with static modifiers are called static methods; they do not need to be instantiated, but are called directly from the class
class Animal {
static isAnimal(a) {
return a instanceofAnimal; }}let a = new Animal('Jack');
Animal.isAnimal(a); // true
a.isAnimal(a); // TypeError: a.isAnimal is not a function
Copy the code
ES7 class usage
Instance attributes
In ES6, instance attributes can only be defined in the constructor this. XXX; in THE ES7 proposal, they can be defined directly in the class
class Animal {
name = 'Jack';
constructor() {
/ /...}}let a = new Animal();
console.log(a.name); //Jack
Copy the code
Static attributes
In the ES7 proposal, you can define a static property using static
class Animal {
static num = 42;
constructor() {
// ...}}console.log(Animal.num); / / 42
Copy the code
TypeScript class usage
Public, private and protected
- Properties or methods decorated by public are public and can be accessed anywhere. By default, all properties and methods are public
- A property or method modified by private is private and cannot be accessed outside the class in which it is declared
- Protected attributes or methods are protected, just like private, except that they are accessible in subclasses
Parameter properties
Modifiers and readonly can also be used in constructor arguments to assign a value to the property as defined in the class, making code more concise
class Animal {
// public name: string;
public constructor(public name) {
// this.name = name;}}Copy the code
readonly
A read-only property keyword that is allowed only in a property 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.
Copy the code
It would be more elegant
class Animal {
// public readonly name;
public constructor(public readonly name) {
// this.name = name;}}Copy the code
An abstract class
Abstract is used to define abstract classes and their abstract methods
Abstract classes are not allowed to be instantiated.
abstract class Animal {
public name;
public constructor(name) {
this.name = name;
}
public abstract sayHi();
}
let a = new Animal('Jack');
Ts (9,11): error TS2511: Cannot create an instance of the abstract class 'Animal'.
Copy the code
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 The ${this.name}`); }}let cat = new Cat('Tom');
Copy the code
The type of the 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 The ${this.name}`; }}let a: Animal = new Animal('Jack');
console.log(a.sayHi()); // My name is Jack
Copy the code
Classes and interfaces
Class implementation interface
Implements is an important concept in object orientation. Features that are common to different classes can be extracted as interfaces, which are implemented using the implements keyword. 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 security door has an alarm function, we can simply add an alarm method to the security door. If you have another class, a car, that also has the function of alarm, you can consider extracting the alarm, as an interface, security door and car to achieve it.
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'); }}Copy the code
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'); }}Copy the code
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;
}
Copy the code
Interface inheritance class
In common object-oriented languages, interfaces cannot inherit from classes, but in TypeScript they can
- Class can be used as a class (
new xx
Create an instance of it. - A class can be used as a type
: xx
Indicates the type of the parameter.
interface PointInstanceType {
x: number;
y: number;
}
/ / equivalent to the
class Point {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y; }}Copy the code
When we declare Interface Point3d extends Point, Point3d actually inherits the type of an instance of the class Point.
In other words, one interface, Point3d, is defined to inherit from another interface, PointInstanceType.
So there is no essential difference between “interface inheriting class” and “interface inheriting 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 extends PointInstanceType
interface Point3d extends Point {
z: number;
}
let point3d: Point3d = {x: 1.y: 2.z: 3};
Copy the code
In addition to constructors, static properties or methods are not included. (The type of an instance should certainly not include constructors, static properties, or static methods.)
That is, declare that the class creates a type that contains instance properties and instance methods
class Point {
/** static attribute, 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 attribute, X-axis value */
x: number;
/** Instance attribute, y value */
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;
Copy the code
Generics
Generics are the feature of defining functions, interfaces, or classes without specifying a specific type in advance.
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 specify or not specify, and type inference will be calculated automatically
createArray<string> (3.'x'); // ['x', 'x', 'x']
createArray(3.'x'); // ['x', 'x', 'x']
Copy the code
Multiple type parameters
function swap<T.U> (tuple: [T, U]) :U.T] {
return [tuple[1], tuple[0]];
}
// A tuple used to exchange input
swap([7.'seven']); // ['seven', 7]
Copy the code
Generic constraint
We use extends to constrain that the generic T must conform to the Lengthwise shape of the interface, that is, it must contain the Length attribute.
If the arG passed in does not contain length when calling loggingIdentity, an error will be reported at compile time:
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'.
Copy the code
Multiple type parameters can also constrain each other by requiring T to inherit from U, which ensures that fields on U that do not exist in T will not appear
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 });
Copy the code
A 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']
Copy the code
A 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; };
Copy the code
The default type of a generic parameter
We can specify default types for type parameters in generics. This default type comes into play when type parameters are not specified directly in the code when using generics and cannot be inferred from the actual value parameters
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;
}
Copy the code
A statement to merge
If you define two functions, interfaces, or classes with the same name, they are merged into one type
Combination of functions
// Overloading 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(' '); }}Copy the code
Merging interfaces
Attributes in interfaces are simply merged into one interface when merged
interface Alarm {
price: number;
weight: number;
}
Copy the code
The type of the merged attribute 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'.
Copy the code
Merging methods in interfaces is the same as merging functions:
interface Alarm {
price: number;
alert(s: string) :string;
}
interface Alarm {
weight: number;
alert(s: string.n: number) :string;
}
Copy the code
The equivalent of
interface Alarm {
price: number;
weight: number;
alert(s: string) :string;
alert(s: string.n: number) :string;
}
Copy the code
Such merger
interface Alarm {
price: number;
weight: number;
alert(s: string) :string;
alert(s: string.n: number) :string;
}
Copy the code
engineering
Code review
In January 2019, TypeScirpt officially decided to fully adopt ESLint as a code checking tool and created a new project, typescript-ESLint, TypeScript file parser @typescript-eslint/parser and related configuration options @typescript-eslint/eslint-plugin are provided.
What is code review
Code inspection is mainly used to find code errors and unify the code style.
In JavaScript projects, we generally use ESLint for code checking, which greatly enriches the scope with its plug-in features and can even be used to check typescript code when paired with typescript-ESLint
Why code review
After compiling with TSC and checking with ESLint, the following error message is reported
var myName = 'Tom';
// esLint reports an 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 reports an 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'?
Copy the code
ES6
Has more advanced syntaxlet
和const
At this point, you can passeslint
Check it out and prompt us to use itlet
或const
Rather thanvar
eslint
Unable to identifymyName
What methods existeslint
You can find sometsc
Don’t care about errors, check out some potential problems, so code review is very important.
Use ESLint in TypeScript
Install ESLint in the project
npm install --save-dev eslint
Since ESLint uses Espree for syntax parsing by default, some TypeScript syntax is not recognized, so we need to install @typescript-esLint /parser instead of the default parser. Don’t forget to install TypeScript as well
npm install --save-dev typescript @typescript-eslint/parser
@typescript-eslint/eslint-plugin It supplements the esLint default rules by providing some additional rules applicable to ts syntax
npm install --save-dev @typescript-eslint/eslint-plugin
Creating a Configuration File
ESLint needs a configuration file to determine which rules to check, typically named.eslintrc.js or.eslintrc.json
When running ESLint to check a file, it will first try to read the configuration file in the directory in which the file is stored, then go up one level and combine the found configuration as the configuration of the file being checked
Create.eslintrc.js in the root directory of your project with the following contents:
module.exports = {
parser: '@typescript-eslint/parser'.plugins: ['@typescript-eslint'].rules: {
// Do not use var
'no-var': "error".// Use interface instead of type
'@typescript-eslint/consistent-type-definitions': [
"error"."interface"]}}Copy the code
In the configuration above, we specified two rules, where no-var is a rule native to ESLint, @typescript-eslint/consistent-type-definitions is a new rule added to @typescript-eslint/eslint-plugin.
Either OFF, WARN, or ERROR, which indicates closure, warning, or error
The meanings of disable, warning, and error are as follows: Disable: This rule is disabled. Warning: An error message is displayed during code check, but it does not affect the exit code error message: When an error is found, not only will an error message be printed, but the exit code will be set to 1.Copy the code
Check a TS file
Create a new file index.ts
var myName = 'Tom';
type Foo = {};
Copy the code
Perform. / node_modules /. Bin/eslint index. The ts
Error received:
/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.Copy the code
It is inconvenient to execute such a long script at a time, but we can simplify this step by creating an NPM script by adding a script to package.json
{
"scripts": {
"eslint": "eslint index.ts"}}Copy the code
Simply execute NPM run ESLint
Review the TS files for the entire project
Project source files are typically stored in the SRC directory, so change the ESLint script in package.json to check a directory instead. Since esLint does not check files with the.ts suffix by default, the argument — ext.ts is required
{
"scripts": {
"eslint": "eslint src --ext .ts"}}Copy the code
NPM run esLint checks all files with the.ts suffix in the SRC directory
Integrate ESLint checking with VSCode
Plugin name: ESLint
The ESLint plugin in VSCode does not check the.ts suffix by default, you need to add the following configuration in “File => Preferences => Settings => Workspace” (you can also create a configuration file in the project root directory.vscode/settings.json) :
{
"eslint.validate": [
"javascript"."javascriptreact"."typescript"]."typescript.tsdk": "node_modules/typescript/lib"
}
Copy the code
Ts file, move the mouse pointer to the red prompt, you can see the error message
Plus automatic repair when saving, modify the configuration file
{
"editor.codeActionsOnSave": {
"source.fixAll": true."source.fixAll.eslint": true
},
"eslint.validate": [
"javascript"."javascriptreact"."typescript"]."typescript.tsdk": "node_modules/typescript/lib"
}
Copy the code
Use Prettier to fix formatting errors
ESLint includes checks for code formats such as Spaces, semicolons, and so on. But a more advanced tool for formatting code in the front-end community is Prettier
Prettier focuses on formatting code, parsing it so that everyone writes the same way
Install the Prettier
npm install --save-dev prettier
Create a file prettier. Config. js that contains the configuration items for Prettier. There are few configuration items for Prettier, so I recommend one
// prettier.config.js or .prettierrc.js
module.exports = {
// A line of up to 100 characters
printWidth: 100.// Use 4 Spaces for indentation
tabWidth: 4.// Instead of indentation, use Spaces
useTabs: false.// A semicolon is required at the end of the line
semi: true.// Use single quotes
singleQuote: true.// The key of the object is quoted only when necessary
quoteProps: 'as-needed'.JSX uses double quotes instead of single quotes
jsxSingleQuote: false.// Do not need a comma at the end
trailingComma: 'none'.// Spaces are required at the beginning and end of braces
bracketSpacing: true.// JSX tag Angle brackets require line breaks
jsxBracketSameLine: false.// Arrow functions with only one argument also need parentheses
arrowParens: 'always'.// The range in which each file is formatted is the entire content of the file
rangeStart: 0.rangeEnd: Infinity.// There is no need to write @prettier at the beginning of the file
requirePragma: false.// There is no need to automatically insert @prettier at the beginning of a file
insertPragma: false.// Use the default line folding standard
proseWrap: 'preserve'.// Depending on the display style, HTML should be folded or not
htmlWhitespaceSensitivity: 'css'.// Use lf for line breaks
endOfLine: 'lf'
};
Copy the code
ESLint configuration using AlloyTeam
There are too many ESLint native rules and @typescript-eslint/eslint-plugin rules, and some of the native rules don’t support typescript well and need to be disabled
The installation
npm install --save-dev eslint typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-config-alloy
Add it under.eslintrc.js
module.exports = {
extends: [
'alloy'.'alloy/typescript',].env: {
// Your environment variables (containing 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 means 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}};Copy the code
Use ESLint to check TSX files
Install eslint plugin – react:
npm install --save-dev eslint-plugin-react
Eslint adds the.tsx suffix to package.json
{
"scripts": {
"eslint": "eslint src --ext .ts,.tsx"}}Copy the code
New typescriptreact check in VSCode configuration
{
"eslint.validate": [
"typescriptreact"],}Copy the code