“1.8W” is a rare TS learning guide

Time:2021-7-29

Apotheker first used typescript in the angular 2. X project. At that time, typescript had not entered the public’s vision. However, there are more and more partners learning typescript. In this article, Po will learn from16Start with three aspects and take you step by step to learn typescript. Don’t miss it if you are interested.

1、 What is typescript

Typescript is an open source programming language developed by Microsoft. It is a superset of JavaScript and essentially adds optional static types and class based object-oriented programming to the language.

Typescript provides the latest and evolving JavaScript features, including those from ECMAScript in 2015 and future proposals, such as asynchronous functions and decorators, to help build robust components. The following figure shows the relationship between typescript and Es5, es2015 and es2016:

1.1 difference between typescript and JavaScript

TypeScript JavaScript
A superset of JavaScript is used to solve the code complexity of large projects A scripting language for creating dynamic web pages
Errors can be found and corrected during compilation As an interpretive language, errors can only be found at run time
Strong type, supports static and dynamic types Weak type, no static type option
Finally, it is compiled into JavaScript code so that the browser can understand it It can be used directly in the browser
Supports modules, generics, and interfaces Modules, generics, or interfaces are not supported
Community support is still growing and not very large Extensive community support and extensive documentation and problem solving support

1.2 get typescript

The command-line typescript compiler can be installed using the NPM package manager.

1. Install typescript
$ npm install -g typescript
2. Verify typescript
$ tsc -v 
# Version 4.0.2
3. Compile typescript file
$ tsc helloworld.ts
# helloworld.ts => helloworld.js

Of course, it is not necessary to install typescript for young partners who have just startedtypescriptInstead, you can directly use typescript playground online to learn new syntax or new features. Through configurationTS ConfigYou can set different compilation targets to compile and generate different target codes.

The compilation target set in the following example is Es5:

(picture source: https://www.typescriptlang.or… )

1.3 typical typescript workflow

As you can see, the above figure contains three TS files: A.ts, b.ts and c.ts. These files will be compiled into three JS files by typescript compiler according to the configured compilation options, namely A.js, B.js and c.js. For most web projects developed using typescript, we will package the compiled JS files and then deploy them.

1.4 initial experience of typescript

Create a newhello.tsFile and enter the following:

function greet(person: string) {
  return 'Hello, ' + person;
}

console.log(greet("TypeScript"));

Then executetsc hello.tsCommand, and then a compiled file will be generatedhello.js

"use strict";
function greet(person) {
  return 'Hello, ' + person;
}
console.log(greet("TypeScript"));

Looking at the compiled output above, we find thatpersonThe type information of the parameter is erased after compilation. Typescript only statically checks the type during compilation. If an error is found, an error will be reported during compilation. At run time, the compiled JS, like ordinary JavaScript files, will not be type checked.

2、 Typescript base type

2.1 boolean type

let isDone: boolean = false;
// ES5:var isDone = false;

2.2 number type

let count: number = 10;
// ES5:var count = 10;

2.3 string type

let name: string = "semliker";
// ES5:var name = 'semlinker';

2.4 symbol type

const sym = Symbol();
let obj = {
  [sym]: "semlinker",
};

console.log(obj[sym]); // semlinker 

2.5 array type

let list: number[] = [1, 2, 3];
// ES5:var list = [1,2,3];

let list: Array<number> = [1, 2, 3]; //  Array < number > generic syntax
// ES5:var list = [1,2,3];

2.6 enum type

Using enumeration, we can define some constants with names. Enumerations can be used to express intentions clearly or to create a distinct set of use cases. Typescript supports numeric and string based enumeration.

1. Numeric enumeration
enum Direction {
  NORTH,
  SOUTH,
  EAST,
  WEST,
}

let dir: Direction = Direction.NORTH;

By default, the initial value of north is 0, and the remaining members will grow automatically from 1. In other words, the value of direction.south is 1, the value of direction.east is 2, and the value of direction.west is 3.

After compiling the above enumeration examples, the corresponding Es5 code is as follows:

"use strict";
var Direction;
(function (Direction) {
  Direction[(Direction["NORTH"] = 0)] = "NORTH";
  Direction[(Direction["SOUTH"] = 1)] = "SOUTH";
  Direction[(Direction["EAST"] = 2)] = "EAST";
  Direction[(Direction["WEST"] = 3)] = "WEST";
})(Direction || (Direction = {}));
var dir = Direction.NORTH;

Of course, we can also set the initial value of North, such as:

enum Direction {
  NORTH = 3,
  SOUTH,
  EAST,
  WEST,
}
2. String enumeration

In typescript version 2.4, we are allowed to use string enumeration. In a string enumeration, each member must be initialized with a string literal or another string enumeration member.

enum Direction {
  NORTH = "NORTH",
  SOUTH = "SOUTH",
  EAST = "EAST",
  WEST = "WEST",
}

The Es5 codes corresponding to the above codes are as follows:

"use strict";
var Direction;
(function (Direction) {
    Direction["NORTH"] = "NORTH";
    Direction["SOUTH"] = "SOUTH";
    Direction["EAST"] = "EAST";
    Direction["WEST"] = "WEST";
})(Direction || (Direction = {}));

By observing the compilation results of numeric enumeration and string enumeration, we can know that numeric enumeration supportsFrom member name to member valueIn addition to normal mapping, it also supportsFrom member value to member nameReverse mapping of:

enum Direction {
  NORTH,
  SOUTH,
  EAST,
  WEST,
}

let dirName = Direction[0]; // NORTH
let dirVal = Direction["NORTH"]; // 0

In addition, for pure string enumeration, we cannot omit any initializer. If no value is explicitly set for numeric enumeration, it will be initialized with default rules.

3. Constant enumeration

In addition to numeric enumeration and string enumeration, there is a special enumeration – constant enumeration. It is usedconstKeyword modified enumeration, constant enumeration will use inline syntax, and will not compile and generate any JavaScript for enumeration types. In order to better understand this sentence, let’s take a specific example:

const enum Direction {
  NORTH,
  SOUTH,
  EAST,
  WEST,
}

let dir: Direction = Direction.NORTH;

The Es5 codes corresponding to the above codes are as follows:

"use strict";
var dir = 0 /* NORTH */;
4. Heterogeneous enumeration

The member values of heterogeneous enumerations are a mixture of numbers and Strings:

enum Enum {
  A,
  B,
  C = "C",
  D = "D",
  E = 8,
  F,
}

The above Es5 codes are as follows:

"use strict";
var Enum;
(function (Enum) {
    Enum[Enum["A"] = 0] = "A";
    Enum[Enum["B"] = 1] = "B";
    Enum["C"] = "C";
    Enum["D"] = "D";
    Enum[Enum["E"] = 8] = "E";
    Enum[Enum["F"] = 9] = "F";
})(Enum || (Enum = {}));

By observing the Es5 code generated above, we can find that numerical enumeration has more “reverse mapping” than string enumeration:

Console.log (enum. A) // output: 0
Console.log (enum [0]) // output: a

2.7 any type

In typescript, any type can be classified as any type. This makes the any type the top-level type of the type system (also known as the global supertype).

let notSure: any = 666;
notSure = "semlinker";
notSure = false;

anyA type is essentially an escape pod of a type system. As developers, this gives us a lot of freedom: typescript allows us toanyThe value of type performs any operation without performing any form of check in advance. For example:

let value: any;

value.foo.bar; // OK
value.trim(); // OK
value(); // OK
new value(); // OK
value[0][1]; // OK

In many scenarios, this is too loose. useanyType, you can easily write code that is of the correct type but has problems at run time. If we useanyType, you cannot use the large number of protection mechanisms provided by typescript. In order to solveanyTypescript 3.0 introducesunknownType.

2.8 unknown type

Just like all types can be assigned toany, all types can also be assigned tounknown。 This makesunknownBecome another top-level type of typescript type system (the other isany)。 Let’s take a lookunknownUse examples of types:

let value: unknown;

value = true; // OK
value = 42; // OK
value = "Hello World"; // OK
value = []; // OK
value = {}; // OK
value = Math.random; // OK
value = null; // OK
value = undefined; // OK
value = new TypeError(); // OK
value = Symbol("type"); // OK

yesvalueAll assignments to variables are considered to be of the correct type. However, when we try to typeunknownWhat happens when the value of is assigned to other types of variables?

let value: unknown;

let value1: unknown = value; // OK
let value2: any = value; // OK
let value3: boolean = value; // Error
let value4: number = value; // Error
let value5: string = value; // Error
let value6: object = value; // Error
let value7: any[] = value; // Error
let value8: Function = value; // Error

unknownType can only be assigned toanyType andunknownThe type itself. Intuitively, this makes sense: only containers that can hold values of any type can be savedunknownValue of type. After all, we don’t know variablesvalueWhat type of value is stored in.

Now let’s see when we try to typeunknownWhat happens when an operation is performed on the value of. Here’s what we did beforeanyThe same operation as in the chapter:

let value: unknown;

value.foo.bar; // Error
value.trim(); // Error
value(); // Error
new value(); // Error
value[0][1]; // Error

takevalueThe variable type is set tounknownAfter, these operations are no longer considered to be of the correct type. By willanyType changed tounknownType, we have changed the default setting that allows all changes to prohibit any changes.

2.9 tuple type

As we all know, arrays are generally composed of the same type of values, but sometimes we need to store different types of values in a single variable. At this time, we can use tuples。 There is no tuple in JavaScript. Tuple is a unique type in typescript and works like an array.

Tuples can be used to define types with a limited number of unnamed attributes. Each property has an associated type. When using tuples, you must provide the value of each attribute. In order to solve the concept of meta group more intuitively, let’s take a specific example:

let tupleType: [string, boolean];
tupleType = ["semlinker", true];

In the above code, we define atupleTypeVariable whose type is an array of types[string, boolean]Then we initialize the tupletype variable in order of the correct type. Like arrays, we can access elements in tuples through subscripts:

console.log(tupleType[0]); // semlinker
console.log(tupleType[1]); // true

In case of type mismatch during tuple initialization, for example:

tupleType = [true, "semlinker"];

At this point, the typescript compiler will prompt the following error message:

[0]: Type 'true' is not assignable to type 'string'.
[1]: Type 'string' is not assignable to type 'boolean'.

Obviously, it is caused by type mismatch. During tuple initialization, we must also provide the value of each attribute, otherwise there will be errors, such as:

tupleType = ["semlinker"];

At this point, the typescript compiler will prompt the following error message:

Property '1' is missing in type '[string]' but required in type '[string, boolean]'.

2.10 void type

In a way, void type seems to be the opposite of any type. It means that there is no type. When a function has no return value, you will usually see that its return value type is void:

//Declare that the return value of the function is void
function warnUser(): void {
  console.log("This is my warning message");
}

The Es5 code generated by compiling the above code is as follows:

"use strict";
function warnUser() {
  console.log("This is my warning message");
}

It should be noted that declaring a variable of void type has no effect, because in strict mode, its value can only beundefined

let unusable: void = undefined;

2.11 null and undefined types

In typescript,undefinedandnullThey have their own typesundefinedandnull

let u: undefined = undefined;
let n: null = null;

2.12 object, object and {} type

1. Object type

Object type is a new type introduced by typescript 2.2. It is used to represent non original types.

// node_modules/typescript/lib/lib.es5.d.ts
interface ObjectConstructor {
  create(o: object | null): any;
  // ...
}

const proto = {};

Object.create(proto);     // OK
Object.create(null);      // OK
Object.create(undefined); // Error
Object.create(1337);      // Error
Object.create(true);      // Error
Object.create("oops");    // Error
2. Object type

Object type: it is the type of instances of all object classes. It is defined by the following two interfaces:

  • The object interface defines the attributes on the object.prototype prototype object;
// node_modules/typescript/lib/lib.es5.d.ts
interface Object {
  constructor: Function;
  toString(): string;
  toLocaleString(): string;
  valueOf(): Object;
  hasOwnProperty(v: PropertyKey): boolean;
  isPrototypeOf(v: Object): boolean;
  propertyIsEnumerable(v: PropertyKey): boolean;
}
  • The objectconstructor interface defines the properties of the object class.
// node_modules/typescript/lib/lib.es5.d.ts
interface ObjectConstructor {
  /** Invocation via `new` */
  new(value?: any): Object;
  /** Invocation via function calls */
  (value?: any): any;
  readonly prototype: Object;
  getPrototypeOf(o: any): any;
  // ···
}

declare var Object: ObjectConstructor;

All instances of the object class inherit all properties in the object interface.

3. {} type

The {} type describes an object without members. An error occurs when you attempt to access any property of a typescript object.

// Type {}
const obj = {};

// Error: Property 'prop' does not exist on type '{}'.
obj.prop = "semlinker";

However, you can still use all the attributes and methods defined on the object type. These attributes and methods can be used implicitly through the prototype chain of javascript:

// Type {}
const obj = {};

// "[object Object]"
obj.toString();

2.13 never type

neverTypes represent the types of values that never exist. For example,neverTypes are the return value types of function expressions or arrow function expressions that always throw exceptions or have no return value at all.

//The function returning never must have an unreachable end point
function error(message: string): never {
  throw new Error(message);
}

function infiniteLoop(): never {
  while (true) {}
}

In typescript, you can use the feature of never type to realize comprehensive inspection. Specific examples are as follows:

type Foo = string | number;

function controlFlowAnalysisWithNever(foo: Foo) {
  if (typeof foo === "string") {
    //Here foo is narrowed to string type
  } else if (typeof foo === "number") {
    //Here foo is narrowed to number type
  } else {
    //Foo here is never
    const check: never = foo;
  }
}

Note that in the else branch, we assign the foo narrowed to never to a never variable that displays the declaration. If all the logic is correct, it should be able to compile here. But if one day your colleague changes the type of foo:

type Foo = string | number | boolean;

However, he forgot to modify it at the same timecontrolFlowAnalysisWithNeverMethod. At this time, the foo type of else branch will be narrowed tobooleanType, so that it cannot be assigned to never type. At this time, a compilation error will be generated. In this way, we can ensure that

controlFlowAnalysisWithNeverMethods always exhaust all possible types of foo. Through this example, we can draw a conclusion:Use never to avoid the new union type without corresponding implementation. The purpose is to write code with absolutely safe type.

3、 Typescript assertion

3.1 type assertion

Sometimes you encounter situations where you know more about a value than typescript. Usually this happens when you clearly know that an entity has a more exact type than its existing type.

Type assertions tell the compiler, “trust me, I know what I’m doing.”. Type assertion is like type conversion in other languages, but it does not carry out special data checking and deconstruction. It has no run-time impact, but works during the compilation phase.

Type assertions take two forms:

1. “Angle bracket” syntax
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
2. As syntax
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;

Assertion not null

In context, when the type checker cannot determine the type, a new suffix expression operator!Can be used to assert that the action object is of non null and non undefined types.Specifically, X! Null and undefined are excluded from the x value field.

So what is the use of non empty assertion operators? Let’s take a look at some usage scenarios of non null assertion operators.

1. Ignore undefined and null types
function myFunc(maybeString: string | undefined | null) {
  // Type 'string | null | undefined' is not assignable to type 'string'.
  // Type 'undefined' is not assignable to type 'string'. 
  const onlyString: string = maybeString; // Error
  const ignoreUndefinedAndNull: string = maybeString!; // Ok
}
2. Ignore undefined type when calling function
type NumGenerator = () => number;

function myFunc(numGenerator: NumGenerator | undefined) {
  // Object is possibly 'undefined'.(2532)
  // Cannot invoke an object which is possibly 'undefined'.(2722)
  const num1 = numGenerator(); // Error
  const num2 = numGenerator!(); //OK
}

because!Non empty assertion operators will be removed from the JavaScript code generated by compilation, so pay special attention in the actual use process. For example, the following example:

const a: number | undefined = undefined;
const b: number = a!;
console.log(b); 

The above TS code will compile and generate the following Es5 Code:

"use strict";
const a = undefined;
const b = a;
console.log(b);

Although in TS code, we use non null assertions to makeconst b: number = a!;Statement can be checked by typescript type checker. But in the generated Es5 code,!The non null assertion operator has been removed, so execute the above code in the browser and output it on the consoleundefined

3.3 determining assignment assertions

In typescript version 2.7, a deterministic assignment assertion is introduced, which allows one to be placed after instance properties and variable declarations!Number to tell typescript that the property will be explicitly assigned. In order to better understand its role, let’s take a specific example:

let x: number;
initialize();
// Variable 'x' is used before being assigned.(2454)
console.log(2 * x); // Error

function initialize() {
  x = 10;
}

Obviously, this exception message means that the variable x is used before assignment. To solve this problem, we can use the assertion of determining assignment:

let x!: number;
initialize();
console.log(2 * x); // Ok

function initialize() {
  x = 10;
}

adoptlet x!: number;When the assignment assertion is determined, the typescript compiler will know that the property will be explicitly assigned.

4、 Type guard

Type protection is an expression that performs runtime checks to ensure that the type is within a certain range.In other words, type protection ensures that a string is a string, although its value can also be a numeric value. Type protection is not completely different from feature detection. Its main idea is to try to detect attributes, methods or prototypes to determine how to deal with values. At present, there are four main ways to realize type protection:

4.1 in keyword

interface Admin {
  name: string;
  privileges: string[];
}

interface Employee {
  name: string;
  startDate: Date;
}

type UnknownEmployee = Employee | Admin;

function printEmployeeInformation(emp: UnknownEmployee) {
  console.log("Name: " + emp.name);
  if ("privileges" in emp) {
    console.log("Privileges: " + emp.privileges);
  }
  if ("startDate" in emp) {
    console.log("Start Date: " + emp.startDate);
  }
}

4.2 typeof keyword

function padLeft(value: string, padding: string | number) {
  if (typeof padding === "number") {
      return Array(padding + 1).join(" ") + value;
  }
  if (typeof padding === "string") {
      return padding + value;
  }
  throw new Error(`Expected string or number, got '${padding}'.`);
}

typeofType protection only supports two forms:typeof v === "typename"andtypeof v !== typename"typename"Must be"number""string""boolean"or"symbol"。 But typescript does not prevent you from comparing with other strings, and the language does not recognize those expressions as type protected.

4.3 instanceof keyword

interface Padder {
  getPaddingString(): string;
}

class SpaceRepeatingPadder implements Padder {
  constructor(private numSpaces: number) {}
  getPaddingString() {
    return Array(this.numSpaces + 1).join(" ");
  }
}

class StringPadder implements Padder {
  constructor(private value: string) {}
  getPaddingString() {
    return this.value;
  }
}

let padder: Padder = new SpaceRepeatingPadder(6);

if (padder instanceof SpaceRepeatingPadder) {
  //The type of the pad is narrowed to 'spacerepeatingpad'
}

4.4 type predicates for custom type protection

function isNumber(x: any): x is number {
  return typeof x === "number";
}

function isString(x: any): x is string {
  return typeof x === "string";
}

5、 Union type and type alias

5.1 joint type

The union type is usually associated withnullorundefinedUse together:

const sayHello = (name: string | undefined) => {
  /* ... */
};

For example, herenameThe type of isstring | undefinedMeans that you canstringorundefinedValue passed tosayHelloFunction.

sayHello("semlinker");
sayHello(undefined);

Through this example, you can intuitively know that the combined type of type A and type B is a type that accepts both a and b values. In addition, for union types, you may encounter the following usage:

let num: 1 | 2 = 1;
type EventNames = 'click' | 'scroll' | 'mousemove';

In the example above12or'click'It is called literal type. It is used to restrict that the value can only be one of several values.

5.2 identifiable joint

Typescript recognizes distinguished unions types, also known as algebraic data types or label unions.It contains three main points: recognizability, joint type and type guard.

The essence of this type is a type protection method combining union type and literal type.If a type is a joint type of multiple types and multiple types contain a public attribute, you can use this public attribute to create different type protection blocks.

1. Identifiable

Recognizability requires that each element in the union type contains a singleton type attribute, such as:

enum CarTransmission {
  Automatic = 200,
  Manual = 300
}

interface Motorcycle {
  vType: "motorcycle"; // discriminant
  make: number; // year
}

interface Car {
  vType: "car"; // discriminant
  transmission: CarTransmission
}

interface Truck {
  vType: "truck"; // discriminant
  capacity: number; // in tons
}

In the above code, we defineMotorcycleCarandTruckThree interfaces, each of which contains onevTypeAttribute, which is called recognizable attribute, while other attributes are only related to the interface of the feature.

2. Joint type

Based on the three interfaces defined above, we can create oneVehicleUnion type:

type Vehicle = Motorcycle | Car | Truck;

Now we can start using itVehicleUnion type, forVehicleType variable, which can represent different types of vehicles.

3. Type guard

Let’s define aevaluatePriceMethod, which is used to calculate the price according to the vehicle type, capacity and evaluation factor. The specific implementation is as follows:

const EVALUATION_FACTOR = Math.PI; 

function evaluatePrice(vehicle: Vehicle) {
  return vehicle.capacity * EVALUATION_FACTOR;
}

const myTruck: Truck = { vType: "truck", capacity: 9.5 };
evaluatePrice(myTruck);

For the above code, the typescript compiler will prompt the following error message:

Property 'capacity' does not exist on type 'Vehicle'.
Property 'capacity' does not exist on type 'Motorcycle'.

The reason is that it does not exist in the motorcycle interfacecapacityProperty, which does not exist for the car interfacecapacityProperties. So, how should we solve the above problems now? At this time, we can use type guard. Let’s refactor the previously definedevaluatePriceMethod, the reconstructed code is as follows:

function evaluatePrice(vehicle: Vehicle) {
  switch(vehicle.vType) {
    case "car":
      return vehicle.transmission * EVALUATION_FACTOR;
    case "truck":
      return vehicle.capacity * EVALUATION_FACTOR;
    case "motorcycle":
      return vehicle.make * EVALUATION_FACTOR;
  }
}

In the above code, we useswitchandcaseOperator to implement type guard to ensure thatevaluatePriceMethod, we can safely accessvehicleObject to correctly calculate the price corresponding to the vehicle type.

5.3 type alias

Type aliases are used to give a type a new name.

type Message = string | string[];

let greet = (message: Message) => {
  // ...
};

6、 Cross type

In typescript, cross type is to combine multiple types into one type. adopt&Operator can overlay existing multiple types into one type, which contains all the required type properties.

type PartialPointX = { x: number; };
type Point = PartialPointX & { y: number; };

let point: Point = {
  x: 1,
  y: 1
}

In the above code, we first definePartialPointXType, then use&Operator to create a newPointType, representing a point with X and Y coordinates, and then defining aPointType and initialize.

6.1 consolidation of foundation type attributes with the same name

Now the problem arises. Suppose that in the process of merging multiple types, some types have the same members, but the corresponding types are inconsistent, such as:

interface X {
  c: string;
  d: string;
}

interface Y {
  c: number;
  e: string
}

type XY = X & Y;
type YX = Y & X;

let p: XY;
let q: YX;

In the above code, both interface X and interface y contain the same member C, but their types are inconsistent. In this case, can the type of member C in XY type or YX type bestringornumberWhat about the type? For example, the following example:

p = { c: 6, d: "d", e: "e" }; 

q = { c: "c", d: "d", e: "e" }; 

Why does the type of member C change after interface X and interface y are mixedneverAnd? This is because the type of member C after mixing isstring & numberThat is, the type of member C can be eitherstringThe type can benumberType. Obviously, this type does not exist, so the type of member C after mixing isnever

6.2 merging of non basic type attributes with the same name

In the above example, the types of internal member C in interface X and interface y are basic data types. What happens if they are non basic data types. Let’s take a concrete example:

interface D { d: boolean; }
interface E { e: string; }
interface F { f: number; }

interface A { x: D; }
interface B { x: E; }
interface C { x: F; }

type ABC = A & B & C;

let abc: ABC = {
  x: {
    d: true,
    e: 'semlinker',
    f: 666
  }
};

console.log('abc:', abc);

After the above code runs successfully, the console will output the following results:

It can be seen from the above figure that when mixing multiple types, if there are the same members and the member type is non basic data type, the combination can be successful.

7、 Typescript function

7.1 difference between typescript function and JavaScript function

TypeScript JavaScript
Containing type No type
Arrow function Arrow function (es2015)
Function type No function type
Required and optional parameters All parameters are optional
Default parameters Default parameters
Remaining parameters Remaining parameters
function overloading No function overload

7.2 arrow function

1. Common grammar
myBooks.forEach(() => console.log('reading'));

myBooks.forEach(title => console.log(title));

myBooks.forEach((title, idx, arr) =>
  console.log(idx + '-' + title);
);

myBooks.forEach((title, idx, arr) => {
  console.log(idx + '-' + title);
});
2. Use examples
//Arrow function not used
function Book() {
  let self = this;
  self.publishDate = 2016;
  setInterval(function () {
    console.log(self.publishDate);
  }, 1000);
}

//Use arrow function
function Book() {
  this.publishDate = 2016;
  setInterval(() => {
    console.log(this.publishDate);
  }, 1000);
}

7.3 parameter type and return type

function createUserId(name: string, id: number): string {
  return name + id;
}

7.4 function type

let IdGenerator: (chars: string, nums: number) => string;

function createUserId(name: string, id: number): string {
  return name + id;
}

IdGenerator = createUserId;

7.5 optional and default parameters

//Optional parameters
function createUserId(name: string, id: number, age?: number): string {
  return name + id;
}

//Default parameters
function createUserId(
  name = "semlinker",
  id: number,
  age?: number
): string {
  return name + id;
}

When you declare a function, you can?Number to define optional parameters, such asage?: numberThis form.In actual use, it should be noted that optional parameters should be placed after ordinary parameters, otherwise compilation errors will be caused

7.6 remaining parameters

function push(array, ...items) {
  items.forEach(function (item) {
    array.push(item);
  });
}

let a = [];
push(a, 1, 2, 3);

7.7 function overloading

Function overloading or method overloading is the ability to create multiple methods with the same name and different parameter numbers or types.

function add(a: number, b: number): number;
function add(a: string, b: string): string;
function add(a: string, b: number): string;
function add(a: number, b: string): string;
function add(a: Combinable, b: Combinable) {
  // type Combinable = string | number;
  if (typeof a === 'string' || typeof b === 'string') {
    return a.toString() + b.toString();
  }
  return a + b;
}

In the above code, we provide multiple function type definitions for the add function to realize function overloading. In typescript, in addition to overloading ordinary functions, we can also overload member methods in classes.

Method overloading refers to a technique in which a method has the same name in the same class, different parameters (different parameter types, different number of parameters or the same number of parameters, different order of parameters) and the matching method is selected to perform operations according to the form of actual parameters. Therefore, the condition that member methods in a class meet overloading is that in the same class, the method names are the same and the parameter lists are different. Let’s take an example of overloaded members:

class Calculator {
  add(a: number, b: number): number;
  add(a: string, b: string): string;
  add(a: string, b: number): string;
  add(a: number, b: string): string;
  add(a: Combinable, b: Combinable) {
  if (typeof a === 'string' || typeof b === 'string') {
    return a.toString() + b.toString();
  }
    return a + b;
  }
}

const calculator = new Calculator();
const result = calculator.add('Semlinker', ' Kakuqo');

It should be noted here that when the typescript compiler handles function overloading, it will look up the overload list and try to use the first overload definition. Use this if it matches. Therefore, when defining overloads, we must put the most accurate definition first. In addition, in the calculator class,add(a: Combinable, b: Combinable){ }It is not part of the overloaded list, so for the add member method, we only define four overloaded methods.

8、 Typescript array

8.1 array deconstruction

let x: number; let y: number; let z: number;
let five_array = [0,1,2,3,4];
[x,y,z] = five_array;

8.2 array expansion operator

let two_array = [0, 1];
let five_array = [...two_array, 2, 3, 4];

8.3 array traversal

let colors: string[] = ["red", "green", "blue"];
for (let i of colors) {
  console.log(i);
}

9、 Typescript object

9.1 object deconstruction

let person = {
  name: "Semlinker",
  gender: "Male",
};

let { name, gender } = person;

9.2 object expansion operator

let person = {
  name: "Semlinker",
  gender: "Male",
  address: "Xiamen",
};

//Assembly object
let personWithAge = { ...person, age: 33 };

//Gets items other than some
let { name, ...rest } = person;

10、 Typescript interface

In object-oriented language, interface is a very important concept. It is the abstraction of behavior, and how to act needs to be implemented 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”.

10.1 shape of object

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

let semlinker: Person = {
  name: "semlinker",
  age: 33,
};

10.2 optional read only attribute

interface Person {
  readonly name: string;
  age?: number;
}

The read-only property is used to limit that the value of an object can only be modified when it is just created. In addition, typescript providesReadonlyArray<T>Type, which is associated withArray<T>Similarly, it just removes all variable methods, so it can ensure that the array can no longer be modified after it is created.

let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = a;
ro[0] = 12; // error!
ro.push(5); // error!
ro.length = 100; // error!
a = ro; // error!

10.3 any attribute

Sometimes we want an interface to allow any other attributes in addition to the required and optional attributes. At this time, we can useIndex signatureTo meet the above requirements.

interface Person {
  name: string;
  age?: number;
  [propName: string]: any;
}

const p1 = { name: "semlinker" };
const p2 = { name: "lolo", age: 5 };
const p3 = { name: "kakuqo", sex: 1 }

10.4 difference between interface and type alias

1.Objects/Functions

Both interface and type aliases can be used to describe the shape of an object or function signature:

Interface

interface Point {
  x: number;
  y: number;
}

interface SetPoint {
  (x: number, y: number): void;
}

Type alias

type Point = {
  x: number;
  y: number;
};

type SetPoint = (x: number, y: number) => void;
2.Other Types

Unlike interface types, type aliases can be used for other types, such as primitive types, union types, and tuples:

// primitive
type Name = string;

// object
type PartialPointX = { x: number; };
type PartialPointY = { y: number; };

// union
type PartialPoint = PartialPointX | PartialPointY;

// tuple
type Data = [number, string];
3.Extend

Both interface and type aliases can be extended, but the syntax is different. In addition, interface and type aliases are not mutually exclusive. Interfaces can extend type aliases, but not vice versa.

Interface extends interface

interface PartialPointX { x: number; }
interface Point extends PartialPointX { 
  y: number; 
}

Type alias extends type alias

type PartialPointX = { x: number; };
type Point = PartialPointX & { y: number; };

Interface extends type alias

type PartialPointX = { x: number; };
interface Point extends PartialPointX { y: number; }

Type alias extends interface

interface PartialPointX { x: number; }
type Point = PartialPointX & { y: number; };
4.Implements

Classes can implement interface or type aliases in the same way, but classes cannot implement union types defined using type aliases:

interface Point {
  x: number;
  y: number;
}

class SomePoint implements Point {
  x = 1;
  y = 2;
}

type Point2 = {
  x: number;
  y: number;
};

class SomePoint2 implements Point2 {
  x = 1;
  y = 2;
}

type PartialPoint = { x: number; } | { y: number; };

// A class can only implement an object type or 
// intersection of object types with statically known members.
class SomePartialPoint implements PartialPoint { // Error
  x = 1;
  y = 2;
}
5.Declaration merging

Unlike type aliases, interfaces can be defined multiple times and are automatically merged into a single interface.

interface Point { x: number; }
interface Point { y: number; }

const point: Point = { x: 1, y: 2 };

11、 Typescript class

11.1 properties and methods of class

In object-oriented language, class is the construction of an object-oriented computer programming language, the blueprint for creating objects, and describes the common attributes and methods of the created objects.

In typescript, we canClassKeyword to define a class:

class Greeter {
  //Static properties
  static cname: string = "Greeter";
  //Member properties
  greeting: string;

  //Constructor - performs initialization
  constructor(message: string) {
    this.greeting = message;
  }

  //Static method
  static getClassName() {
    return "Class name is Greeter";
  }

  //Member method
  greet() {
    return "Hello, " + this.greeting;
  }
}

let greeter = new Greeter("world");

So what are the differences between member attributes and static attributes, and between member methods and static methods? There is no need to explain here. Let’s take a direct look at the Es5 code generated by compilation:

"use strict";
var Greeter = /** @class */ (function () {
    //Constructor - performs initialization
    function Greeter(message) {
      this.greeting = message;
    }
    //Static method
    Greeter.getClassName = function () {
      return "Class name is Greeter";
    };
    //Member method
    Greeter.prototype.greet = function () {
      return "Hello, " + this.greeting;
    };
    //Static properties
    Greeter.cname = "Greeter";
    return Greeter;
}());
var greeter = new Greeter("world");

11.2 ECMAScript private fields

Typescript has been supported since version 3.8ECMAScript private field, use as follows:

class Person {
  #name: string;

  constructor(name: string) {
    this.#name = name;
  }

  greet() {
    console.log(`Hello, my name is ${this.#name}!`);
  }
}

let semlinker = new Person("Semlinker");

semlinker.#name;
//     ~~~~~
// Property '#name' is not accessible outside class 'Person'
// because it has a private identifier.

With general properties (even usingprivateDifferent from the attributes declared by modifiers, the following rules should be kept in mind for private fields:

  • Private field with#Character, sometimes we call it private name;
  • Each private field name is uniquely limited to the class it contains;
  • Typescript accessibility modifiers (such as public or private) cannot be used on private fields;
  • Private fields cannot be accessed outside the contained class or even detected.

11.3 accessors

In typescript, we cangetterandsetterMethod to realize data encapsulation and validity verification to prevent abnormal data.

let passcode = "Hello TypeScript";

class Employee {
  private _fullName: string;

  get fullName(): string {
    return this._fullName;
  }

  set fullName(newName: string) {
    if (passcode && passcode == "Hello TypeScript") {
      this._fullName = newName;
    } else {
      console.log("Error: Unauthorized update of employee!");
    }
  }
}

let employee = new Employee();
employee.fullName = "Semlinker";
if (employee.fullName) {
  console.log(employee.fullName);
}

11.4 inheritance of classes

Inheritance is a hierarchical model that connects classes. It refers to the ability of a class (called subclass or sub interface) to inherit the functions of another class (called parent class or parent interface) and add its own new functions. Inheritance is the most common relationship between classes or interfaces.

Inheritance is an is-a relationship:

In typescript, we canextendsKeyword to implement inheritance:

class Animal {
  name: string;
  
  constructor(theName: string) {
    this.name = theName;
  }
  
  move(distanceInMeters: number = 0) {
    console.log(`${this.name} moved ${distanceInMeters}m.`);
  }
}

class Snake extends Animal {
  constructor(name: string) {
    super(name); //  Call the constructor of the parent class
  }
  
  move(distanceInMeters = 5) {
    console.log("Slithering...");
    super.move(distanceInMeters);
  }
}

let sam = new Snake("Sammy the Python");
sam.move();

11.5 abstract classes

useabstractThe class declared by keyword is called abstract class. An abstract class cannot be instantiated because it contains one or more abstract methods. The so-called abstract method refers to a method that does not contain a specific implementation:

abstract class Person {
  constructor(public name: string){}

  abstract say(words: string) :void;
}

// Cannot create an instance of an abstract class.(2511)
const lolo = new Person(); // Error

Abstract classes cannot be instantiated directly. We can only instantiate subclasses that implement all abstract methods. The details are as follows:

abstract class Person {
  constructor(public name: string){}

  //Abstract method
  abstract say(words: string) :void;
}

class Developer extends Person {
  constructor(name: string) {
    super(name);
  }
  
  say(words: string): void {
    console.log(`${this.name} says ${words}`);
  }
}

const lolo = new Developer("lolo");
lolo.say("I love ts!"); // lolo says I love ts!

Class 11.6 method overload

In the previous chapter, we have introduced function overloading. For class methods, it also supports overloading. For example, in the following example, we overloadedProductServiceClassgetProductsMember method:

class ProductService {
    getProducts(): void;
    getProducts(id: number): void;
    getProducts(id?: number) {
      if(typeof id === 'number') {
          Console.log ('Get product information with ID ${ID} ');
      } else {
          Console.log ('Get all product information ');
      }  
    }
}

const productService = new ProductService();
productService.getProducts(666); //  Obtain product information with ID 666
productService.getProducts(); //  Get all product information

12、 Typescript generics

In software engineering, we should not only create consistent and well-defined APIs, but also consider reusability. Components can support not only current data types, but also future data types, which provides you with very flexible functions when creating large-scale systems.

In languages like c# and Java, generics can be used to create reusable components. A component can support multiple types of data. This allows users to use components with their own data types.

The key purpose of designing generics is to provide meaningful constraints between members, which can be instance members of a class, methods of a class, function parameters and function return values.

Generics is a template that allows the same function to accept different types of parameters. Using generics to create reusable components is better than using any types, because generics retain parameter types.

12.1 generic syntax

For readers new to typescript generics, it’s the first time to see<T>Grammar is strange. In fact, it’s nothing special. Just like passing parameters, we pass the type we want to use for a specific function call.

Refer to the picture above when we call identity<Number>(1)NumberTypes are like parameters1Like, it will appear inTThe type is populated anywhere in the. In the figure<T>InternalTCalled a type variable, it is a type placeholder that we want to pass to the identity function, and it is assigned tovalueParameter is used instead of its type: at this timeTIt acts as a type, not a specific number type.

amongTrepresentativeType, usually used as the first type variable name when defining a generic type. But actuallyTYou can use any valid name instead. exceptTIn addition, the following are the meanings represented by common generic variables:

  • K (key): indicates the key type in the object;
  • V (value): indicates the value type in the object;
  • E (element): indicates the element type.

In fact, we can not define only one type variable. We can introduce any number of type variables we want to define. For example, we introduce a new type variableU, used to extend our definedidentityFunction:

function identity <T, U>(value: T, message: U) : T {
  console.log(message);
  return value;
}

console.log(identity<Number, string>(68, "Semlinker"));

In addition to explicitly setting values for type variables, a more common approach is to make the compiler automatically select these types, thus making the code more concise. We can completely omit angle brackets, such as:

function identity <T, U>(value: T, message: U) : T {
  console.log(message);
  return value;
}

console.log(identity(68, "Semlinker"));

For the above code, the compiler is smart enough to know our parameter types and assign them to T and u without requiring the developer to explicitly specify them.

12.2 generic interfaces

interface GenericIdentityFn<T> {
  (arg: T): T;
}

12.3 generic classes

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;
};

12.4 generic tool types

For the convenience of developers, typescript has built-in some common tool types, such as partial, required, readonly, record and ReturnType. For space reasons, we only briefly introduce the partial tool types here. However, before the specific introduction, we have to introduce some relevant basic knowledge to facilitate readers to learn other types of tools by themselves.

1.typeof

In typescript,typeofOperator can be used to get the type of a variable declaration or object.

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

const sem: Person = { name: 'semlinker', age: 33 };
type Sem= typeof sem; // -> Person

function toArray(x: number): Array<number> {
  return [x];
}

type Func = typeof toArray; // -> (x: number) => number[]
2.keyof

keyofThe operator was introduced in typescript version 2.1. It can be used to obtain all keys of a certain type, and its return type is union type.

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

type K1 = keyof Person; // "name" | "age"
type K2 = keyof Person[]; // "length" | "toString" | "pop" | "push" | "concat" | "join" 
type K3 = keyof { [x: string]: Person };  // string | number

Two kinds of index signatures are supported in typescript, digital index and string index:

interface StringArray {
  //String index - > keyof stringarray = > string | number
  [index: string]: string; 
}

interface StringArray1 {
  //Numeric index - > keyof stringarray1 = > number
  [index: number]: string;
}

In order to support two index types at the same time, the return value of digital index must be a subclass of the return value of string index.The reason is that when using numerical index, JavaScript will first convert the numerical index into string index when performing index operation。 thereforekeyof { [x: string]: Person }The result will be returnedstring | number

3.in

inUsed to traverse enumeration types:

type Keys = "a" | "b" | "c"

type Obj =  {
  [p in Keys]: any
} // -> { a: any, b: any, c: any }
4.infer

In a conditional type statement, you can useinferDeclare a type variable and use it.

type ReturnType<T> = T extends (
  ...args: any[]
) => infer R ? R : any;

In the above codeinfer RIt is to declare a variable to carry the return value type of the incoming function signature. In short, it is used to get the type of the function return value for later use.

5.extends

Sometimes the generics we define do not want to be too flexible or inherit some classes. You can add generics constraints through the extends keyword.

interface Lengthwise {
  length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
  console.log(arg.length);
  return arg;
}

Now this generic function has constraints defined, so it is no longer applicable to any type:

loggingIdentity(3);  // Error, number doesn't have a .length property

In this case, we need to pass in the value conforming to the constraint type, which must contain the required attributes:

loggingIdentity({length: 10, value: 3});
6.Partial

Partial<T>The function of is to make all the attributes in a type optional?

definition:

/**
 * node_modules/typescript/lib/lib.es5.d.ts
 * Make all properties in T optional
 */
type Partial<T> = {
  [P in keyof T]?: T[P];
};

In the above code, first passkeyof TGetTAll property names, and then useinTraverse and assign the value toPFinally, throughT[P]Get the corresponding attribute value. middle?Number to make all attributes optional.

Example:

interface Todo {
  title: string;
  description: string;
}

function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) {
  return { ...todo, ...fieldsToUpdate };
}

const todo1 = {
  title: "Learn TS",
  description: "Learn TypeScript",
};

const todo2 = updateTodo(todo1, {
  description: "Learn TypeScript Enum",
});

On topupdateTodoIn the method, we usePartial<T>Tool type, definitionfieldsToUpdateThe type of isPartial<Todo>, i.e.:

{
   title?: string | undefined;
   description?: string | undefined;
}

13、 Typescript decorator

13.1 what is the decorator

  • It is an expression
  • After the expression is executed, a function is returned
  • The input parameters of the function are target, name and descriptor respectively
  • After the function is executed, the descriptor object may be returned to configure the target object

13.2 classification of decorators

  • Class decorators
  • Property decorators
  • Method decorators
  • Parameter decorators

It should be noted that to enable the experimental decorator feature, you must be on the command line ortsconfig.jsonEnable inexperimentalDecoratorsCompiler options:

command line

tsc --target ES5 --experimentalDecorators

tsconfig.json

{
  "compilerOptions": {
     "target": "ES5",
     "experimentalDecorators": true
   }
}

Class 13.3 trimmer

Class decorator declaration:

declare type ClassDecorator = <TFunction extends Function>(
  target: TFunction
) => TFunction | void;

Class decorators, as the name suggests, are used to decorate classes. It receives a parameter:

  • Target: tfunction – decorated class

After the first look, do you feel bad. It’s okay. Let’s give an example right away:

function Greeter(target: Function): void {
  target.prototype.greet = function (): void {
    console.log("Hello Semlinker!");
  };
}

@Greeter
class Greeting {
  constructor() {
    //Internal implementation
  }
}

let myGreeting = new Greeting();
(myGreeting as any).greet(); // console output: 'Hello Semlinker!';

In the above example, we definedGreeterClass decorator, and we used@GreeterUse sugar to decorate.

Friendly tip: readers can directly copy the above code and run it in typescript playground to view the results.

Some readers may want to ask, the example is always outputHello Semlinker!, can I customize the greetings output? That’s a good question. The answer is yes.

The specific implementation is as follows:

function Greeter(greeting: string) {
  return function (target: Function) {
    target.prototype.greet = function (): void {
      console.log(greeting);
    };
  };
}

@Greeter("Hello TS!")
class Greeting {
  constructor() {
    //Internal implementation
  }
}

let myGreeting = new Greeting();
(myGreeting as any).greet(); // console output: 'Hello TS!';

13.4 attribute decorator

Property decorator declaration:

declare type PropertyDecorator = (target:Object, 
  propertyKey: string | symbol ) => void;

As the name suggests, the property decorator is used to decorate the properties of a class. It receives two parameters:

  • Target: Object – decorated class
  • Propertykey: string | symbol – the property name of the decorated class

Strike while the iron is hot. Let’s take an example to warm up:

function logProperty(target: any, key: string) {
  delete target[key];

  const backingField = "_" + key;

  Object.defineProperty(target, backingField, {
    writable: true,
    enumerable: true,
    configurable: true
  });

  // property getter
  const getter = function (this: any) {
    const currVal = this[backingField];
    console.log(`Get: ${key} => ${currVal}`);
    return currVal;
  };

  // property setter
  const setter = function (this: any, newVal: any) {
    console.log(`Set: ${key} => ${newVal}`);
    this[backingField] = newVal;
  };

  // Create new property with getter and setter
  Object.defineProperty(target, key, {
    get: getter,
    set: setter,
    enumerable: true,
    configurable: true
  });
}

class Person { 
  @logProperty
  public name: string;

  constructor(name : string) { 
    this.name = name;
  }
}

const p1 = new Person("semlinker");
p1.name = "kakuqo";

The above code defines alogPropertyFunction to track user operations on attributes. When the code runs successfully, the following results will be output on the console:

Set: name => semlinker
Set: name => kakuqo

13.5 method decorator

Method decorator declaration:

declare type MethodDecorator = <T>(target:Object, propertyKey: string | symbol,          
  descriptor: TypePropertyDescript<T>) => TypedPropertyDescriptor<T> | void;

Method decorators, as the name suggests, are used to decorate methods of classes. It receives three parameters:

  • Target: Object – decorated class
  • Propertykey: string | symbol – method name
  • Descriptor: typepropertydescriptor – property descriptor

Without much nonsense, let’s go straight to the example:

function log(target: Object, propertyKey: string, descriptor: PropertyDescriptor) {
  let originalMethod = descriptor.value;
  descriptor.value = function (...args: any[]) {
    console.log("wrapped function: before invoking " + propertyKey);
    let result = originalMethod.apply(this, args);
    console.log("wrapped function: after invoking " + propertyKey);
    return result;
  };
}

class Task {
  @log
  runTask(arg: any): any {
    console.log("runTask invoked, args: " + arg);
    return "finished";
  }
}

let task = new Task();
let result = task.runTask("learn ts");
console.log("result: " + result);

After the above code runs successfully, the console will output the following results:

"wrapped function: before invoking runTask" 
"runTask invoked, args: learn ts" 
"wrapped function: after invoking runTask" 
"result: finished" 

Let’s introduce the parameter decorator.

13.6 parameter decorator

Parameter decorator declaration:

declare type ParameterDecorator = (target: Object, propertyKey: string | symbol, 
  parameterIndex: number ) => void

As the name suggests, the parameter decorator is used to decorate function parameters. It receives three parameters:

  • Target: Object – decorated class
  • Propertykey: string | symbol – method name
  • Parameterindex: number – the index value of the parameter in the method
function Log(target: Function, key: string, parameterIndex: number) {
  let functionLogged = key || target.prototype.constructor.name;
  console.log(`The parameter in position ${parameterIndex} at ${functionLogged} has
    been decorated`);
}

class Greeter {
  greeting: string;
  constructor(@Log phrase: string) {
    this.greeting = phrase; 
  }
}

After the above code runs successfully, the console will output the following results:

"The parameter in position 0 at Greeter has been decorated" 

14、 What’s new in typescript 4.0

Typescript 4.0 has brought many new features. Here we will briefly introduce only two of them.

14.1 class attribute inference of constructor

WhennoImplicitAnyAfter the configuration property is enabled, typescript 4.0 can use control flow analysis to confirm the property types in the class:

class Person {
  fullName; // (property) Person.fullName: string
  firstName; // (property) Person.firstName: string
  lastName; // (property) Person.lastName: string

  constructor(fullName: string) {
    this.fullName = fullName;
    this.firstName = fullName.split(" ")[0];
    this.lastName =   fullName.split(" ")[1];
  }  
}

However, for the above code, if typescript is before version 4.0, such as version 3.9.2, the compiler will prompt the following error message:

class Person {
  // Member 'fullName' implicitly has an 'any' type.(7008)
  fullName; // Error
  firstName; // Error
  lastName; // Error

  constructor(fullName: string) {
    this.fullName = fullName;
    this.firstName = fullName.split(" ")[0];
    this.lastName =   fullName.split(" ")[1];
  }  
}

It is convenient to infer the type of class attribute from constructor. However, in the process of use, if we can’t guarantee that all member attributes are assigned, the attribute may be considered asundefined

class Person {
   fullName;  // (property) Person.fullName: string
   firstName; // (property) Person.firstName: string | undefined
   lastName; // (property) Person.lastName: string | undefined

   constructor(fullName: string) {
     this.fullName = fullName;
     if(Math.random()){
       this.firstName = fullName.split(" ")[0];
       this.lastName =   fullName.split(" ")[1];
     }
   }  
}

14.2 marked tuple elements

In the following example, we use tuple types to declare the types of the remaining parameters:

function addPerson(...args: [string, number]): void {
  console.log(`Person info: name: ${args[0]}, age: ${args[1]}`)
}

addPerson("lolo", 5); // Person info: name: lolo, age: 5 

In fact, for the aboveaddPersonFunction, we can also implement it as follows:

function addPerson(name: string, age: number) {
  console.log(`Person info: name: ${name}, age: ${age}`)
}

There seems to be little difference between the two methods, but for the first method, we can’t set the names of the first parameter and the second parameter. Although this has no impact on type checking, the lack of tags in tuple positions makes them difficult to use. In order to improve developers’ experience of using tuples, typescript 4.0 supports labeling tuple types:

function addPerson(...args: [name: string, age: number]): void {
  console.log(`Person info: name: ${args[0]}, age: ${args[1]}`);
}

After that, when we useaddPersonMethod, typescript’s smart tips become more friendly.

//Smart tips for unused labels
// addPerson(args_0: string, args_1: number): void
function addPerson(...args: [string, number]): void {
  console.log(`Person info: name: ${args[0]}, age: ${args[1]}`)
} 

//Smart tips for used labels
// addPerson(name: string, age: number): void
function addPerson(...args: [name: string, age: number]): void {
  console.log(`Person info: name: ${args[0]}, age: ${args[1]}`);
}

15、 Compilation context

15.1 function of tsconfig.json

  • Used to identify the root path of the typescript project;
  • Used to configure typescript compiler;
  • Specifies the file to compile.

15.2 important fields of tsconfig.json

  • Files – sets the name of the file to compile;
  • Include – sets the files to be compiled and supports path pattern matching;
  • Exclude – sets files that do not need to be compiled and supports path pattern matching;
  • Compileroptions – sets options related to the compilation process.

15.3 compiler options

Compiler options supports many options, includingbaseUrltargetbaseUrlmoduleResolutionandlibWait.

The detailed description of each option of compileroptions is as follows:

{
  "compilerOptions": {

    /*Basic options*/
    "Target": "Es5", // specify the ECMAScript target version: 'Es3' (default), 'Es5', 'ES6' / 'es2015', 'es2016', 'es2017', or 'esnext'
    "Module": "commonjs"
    "Lib": [], // specify the library files to be included in the compilation
    "Allowjs": true, // allow JavaScript files to be compiled
    "Checkjs": true, // reports errors in JavaScript files
    "JSX": "preserve", // specify the generation of JSX Code: 'preserve', 'react native', or 'react'
    "Declaration": true, // generate the corresponding '. D.ts' file
    "Sourcemap": true, // generate the corresponding '. Map' file
    "Outfile": ". /", // merge output files into one file
    "Outdir": ". /", // specify the output directory
    "Rootdir": ". /", // used to control the output directory structure -- outdir
    "Removecomments": true, // delete all comments after compilation
    "Noemit": true, // no output file will be generated
    "Importhelpers": true, // import auxiliary tool functions from tslib
    "Isolatedmodules": true, // treat each file as a separate module (similar to 'ts.transpilemodule')

    /*Strict type check options*/
    "Strict": true, // enable all strict type checking options
    "Noimplicatany": true, // an error is reported when there is an implied any type on the expression and declaration
    "Strictnullchecks": true, // enable strict null checks
    "Noimplicitthis": true, // an error is generated when the value of this expression is of type any
    "Alwaysstrict": true, // check each module in strict mode, and add 'use strict' to each file

    /*Additional inspection*/
    "Nounusedlocals": true, // an error is thrown when there are unused variables
    "Nounusedparameters": true, // an error is thrown when there are unused parameters
    "Noimplicitreturns": true, // an error is thrown when not all the codes in the function have return values
    "Nofallthroughcasesinswitch": true, // reports the fallthrough error of the switch statement( That is, the case statement of switch is not allowed to run through)

    /*Module resolution options*/
    "Moduleresolution": "node", // select a module Resolution Policy: 'node' (node. JS) or 'classic' (typescript pre-1.6)
    "Baseurl": ". /", // used to resolve the base directory of non relative module names
    "Paths": {}, // list of module name to baseurl based path mappings
    "Rootdirs": [], // a list of root folders whose combined contents represent the structural contents of the project runtime
    "Typeroots": [], // list of files containing type declarations
    "Types": [], // list of file names of type declarations to be included
    "Allowsynthetic defaultimports": true, // allows default imports from modules that do not have default exports set.

    /* Source Map Options */
    "Sourceroot": ". /", // specify the location where the debugger should find the typescript file instead of the source file
    "Maproot": ". /", // specify the location where the debugger should find the mapping file instead of the generation file
    "Inlinesourcemap": true, // generate a single souemaps file instead of generating sourcemaps into different files
    "Inlinesources": true, // generate the code and sourcemaps into a file. The -- inlinesourcemap or -- sourcemap attribute must be set at the same time

    /*Other options*/
    "Experimentaldecorators": true, // enable decorators
    "Emitdecoratormetadata": true // provides metadata support for decorators
  }
}

16、 Typescript development aids

16.1 TypeScript Playground

Introduction: typescript is an online typescript running environment officially provided by typescript. With it, you can easily learn the relevant knowledge of typescript and the functional features of different versions.

Online address: https://www.typescriptlang.or…

In addition to the official playground of typescript, you can also choose other playgrounds, such as codepen.io, stackblitz or jsbin.com.

16.2 TypeScript UML Playground

Introduction: an online typescript UML tool, with which you can generate UML class diagrams for the specified typescript code.

Online address: https://tsuml-demo.firebaseap…

16.3 JSON TO TS

Introduction: a typescript online tool. With it, you can generate the corresponding typescript interface definition for the specified JSON data.

Online address: http://www.jsontots.com/

In addition to using the jsontots online tool, for those who use the vscode IDE, you can also install the JSON to TS extension to complete it quicklyJSON to TSConversion work.

16.4 Schemats

Introduction: with schemas, you can automatically generate typescript interface definitions based on the schema in the (Postgres, MySQL) SQL database.

Online address: https://github.com/SweetIQ/sc…

16.5 TypeScript AST Viewer

Introduction: a typescript ast online tool, you can view the ast (abstract syntax tree) abstract syntax tree corresponding to the specified typescript code.

Online address: https://ts-ast-viewer.com/

For small partners who have known ast, AST explorer, an online tool, should not be unfamiliar. In addition to supporting JavaScript, the tool also supports parsing of CSS, JSON, regexp, graphql, markdown and other formats.

16.6 TypeDoc

Introduction: typedoc is used to convert comments in typescript source code into HTML documents or JSON models. It can be flexibly extended and supports a variety of configurations.

Online address: https://typedoc.org/

16.7 TypeScript ESLint

Introduction: using typescript eslint can help us standardize code quality and improve team development efficiency.

Online address: https://typescript-eslint.io/

For partners who are interested in typescript eslint project and want to apply it in the project, please refer to the article “how to use eslint and prettier gracefully in typescript project”.

If you can insist on seeing that all the little partners here are “true love”, if you still want to finish, take a look at the 1.8K + open source project on GitHub: awesome typescript.

https://github.com/semlinker/…

17、 Reference resources

  • mariusschulz – the-unknown-type-in-typescript
  • Deep understanding of typescript – compilation context
  • TypeScript 4.0
  • TypeScript Quickly

18、 Recommended reading

  • Great DeNO beginner level chapter
  • Great DeNO combat tutorial
  • You don’t know, blob
  • You don’t know the weakmap