Introduce TypeScript

The type of programming language

  • Dynamically typed language

    Is a language for datatype checking at run time. In dynamically typed languages such as JavaScript and Python, there is no need to specify a data type for a variable. The first time a value is assigned to a variable, the data type is recorded internally. Errors can only be found at run time, so they may cause some problems. Common static type code checkers are EsLint. Prompt problems according to rules during coding.

  • Statically typed language

    Is a language for datatype checking at compile time. When writing programs, you need to declare the data type of variables, such as C, Java.

What is TypeScript?

  • TypeScript transforms type-less dynamic languages into type-focused static languages, which are extensible JavaScript, a superset of JavaScript. In addition to native JavaScript, it also provides a type system.

  • Provides ES6 syntax support.

  • Compatible with various browsers and systems, open source.

The TypeScript’s official website

Why use TypeScript?

  • The program is easier to understand

    When you want to know the parameter types of a function method, the code is all comments.

  • More efficient

    Different code blocks and definitions for jump, automatic code completion, rich interface prompts.

  • Fewer mistakes

    Most errors are found at compile time.

  • Very inclusive

    Fully JavaScript compatible, third-party libraries can write type files separately, and most projects support TypeScript.

Install the TypeScript

Install the TypeScript:

npm install -g typescript
Copy the code

View version:

tsc -v
Copy the code

TSC stands for TypeScript Compiler.

Create a TS file:

// hello.ts
// Specify that the name argument is of type string
const hello = (name: string) = > {
  return `hello ${name}`;
}

hello('ts');
Copy the code

Compile to js file:

tsc hello.ts
Copy the code

A new js file is generated:

// hello.js
var hello = function (name) {
    return "hello ".concat(name);
};
hello('ts');
Copy the code

If there is a problem in the ts file, an error will be reported:

// hello.ts
const hello = (name: string) = > {
  return `hello ${name}`;
}

// 123 is not a string
hello(123);
Copy the code
> tsc hello.ts
hello.ts:5:7 - error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.

5 hello(123);
        ~~~


Found 1 error.
Copy the code

Js files will still be generated:

// hello.js
var hello = function (name) {
    return "hello ".concat(name);
};
hello(123);
Copy the code

As you can see, TSC compilation generates results even if an error is reported.

Primitive type and any type

Primitive and any declarations:

let bool: boolean = true;

let num: number = 10;

let str: string = 'ts';
let tempStr: string = `Hello, ${str}`;

let u: undefined = undefined;

let n: null = null;

// undefined and null are subtypes of all types and can be assigned to variables of other types
num = undefined;

let big: bigint = 1n;

let sym: symbol = Symbol(a);// The any type is the top-level type of the type system. Any type can be classified as any
let anyType: any = 123;
anyType = 'string';
anyType = true;

// You can access any properties and methods of any objects
anyType.name;
anyType.add();
Copy the code

Undefined vs. null

  • Similarity: undefined and null are both turned to false in if statements.

  • Original idea: Distinguish null values of primitive and synthesized types. Define a null value of the primitive type as undefined and NaN when converted to a number; A null value of the synthesized type is defined as null, which is 0 when converted to a number. In the end, it’s impossible to tell.

  • Current usage: null means “no object”, there should be no value; Undefined means “missing value”. There should be a value, but it is not defined yet.

Arrays and tuples

// Arrays aggregate data of the same type
let arr: number[] = [1.2];
arr.push(3);

// Class arraylike object cannot use array methods
function foo() {
  console.log(arguments);
}

// triple sets the data type of each item. Tuples are arrays
let user: [string.number] = ['Joe'.20];
// The value using the array push can only be one of the types defined by the tuple
user.push(30);
Copy the code

Interface Interface

An interface is a description of the shape of an Object. Using an interface can help define an Object type.

Interface is a duck type. It is more concerned with how the object is used than with the object type itself.

Interface is not a concept in JS and will not be converted to JS after compilation. It can only be used for static type checking.

interface Person {
  name: string;
  // Optional attributeage? :number;
  // A read-only property that can only be assigned at creation time
  // readonly for attributes, const for variables
  readonly id: number;
}

let Joe: Person = {
  name: 'Joe'.age: 20.id: 1
}

// Joe.id = 2; "Id" cannot be assigned because it is a read-only property.
Copy the code

An Interface is like a specification and a contract, with a warning if it is different.

function

The function is a first-class citizen. Functions, like other types of objects, can be taken as arguments, stored in arrays, assigned to variables, and so on.

A function consists of two parts: input and output.

// Specify the input and output of the function
// Function declaration
function add(x: number, y: number./* This parameter is optionalz? :number) :number {
  if (typeof z === 'number') {
    return x + y + z;
  } else {
    returnx + y; }}let result: number = add(1.2); / / 3

// Function expression
const add1 = (x: number.y: number) :number= > {
  return x + y;
}

// interface describes the function type
interface ISum {
  // Parameter type: return value type
  (x: number.y: number) :number
}

const add2: ISum = add1;
Copy the code

Type inference

Type inference automatically defines the type of a variable at assignment time.

// Type inference
let str = 'str';
// str = 123; Type "number" cannot be assigned to type "string".
// If no value is assigned, the variable is defined as any and is not type-checked

// The any type allows variables to be changed to any type
Copy the code

The joint type

A union type enables a variable to be one of multiple types.

// union types
// It is defined as number or string, and can only access the common attributes of both types
let numOrStr: number | string;
numOrStr = "123";
numOrStr = 123;
// numOrStr.length; The attribute "length" does not exist on type "number".
Copy the code

Types of assertions

Type assertions use AS to tell the compiler that you know the type better than it does, and to keep it from reporting errors.

// type assertion Type assertion
function getLength(input: string | number) :number {
  const str = input as string;
  if (str.length) {
    return str.length;
  } else {
    const number = input as number;
    return number.toString().length; }}Type assertions are not type conversions and can only be asserted to defined types
Copy the code

Type the guards

Federated types are automatically narrowed down by conditional statements and typeof Instanceof.

// type guard Type guard
function getLength2(input: string | number) :number {
  if (typeof input === "string") {
    return input.length;
  }
  else {
    // The input of this branch is of type number, intelligently narrowing the scope
    returninput.toString().length; }}Copy the code

Class Class

Class basics

  • Class: Defines the abstract characteristics of everything

  • Object: An instance of a class

  • Three characteristics of object-oriented: encapsulation (hide the details of data operations, only expose the interface of the operation), inheritance (subclasses inherit from the parent class, and can have more features), polymorphism (inheritance of different classes can have different responses to the same method)

Class in the TypeScript

  • Three modifiers provide permission management: public (callable anywhere, default), private (not externally callable), and protected (accessible in subclasses)

  • Readonly Read-only property that cannot be modified.

/ / class
class Animal {
  readonly name: string;
  constructor(name) {
    this.name = name
  }
  run() {
    return `The ${this.name} is running`}}/ / object
const snake = new Animal('lily')
// snake.name = 'Joe'; "Name" cannot be assigned because it is a read-only property.
console.log(snake.run()) // lily is running

/ / inheritance
class Dog extends Animal {
  bark() {
    return `The ${this.name} is barking`}}const xiaobao = new Dog('xiaobao')
console.log(xiaobao.run()) // xiaobao is running
console.log(xiaobao.bark()) // xiaobao is barking

/ / polymorphism
class Cat extends Animal {
  static categories = ['mammal'] // Static attributes do not need to be instantiated
  constructor(name) {
    super(name)
    console.log(this.name) // maomao
  }
  run() {
    return 'Meow, ' + super.run()
  }
}
const maomao = new Cat('maomao')
console.log(maomao.run()) // Meow, maomao is running
console.log(Cat.categories) // [ 'mammal' ]

Copy the code

Classes and interfaces

  • Inheritance dilemma: A class can only inherit from another class

  • Classes can implement interfaces using implements

interface Radio {
  switchRadio(trigger: boolean) :void;
}

interface Battery {
  checkBatteryStatus(): void;
}

// Interface inheritance
interface RadioWithBattery extends Radio, Battery {
}

class Car implements Radio {
  switchRadio(trigger: boolean) {
    // todo...}}// class Cellphone implements Radio, Battery {
class Cellphone implements RadioWithBattery {
  switchRadio(trigger: boolean) {
    // todo...
  }
  checkBatteryStatus() {
    // todo...}}Copy the code

Enum enumeration

We sometimes use a range of constants whose values can be represented by enumerations.

Numeric enumeration:

// Enumeration of numbers
enum Direction {
  // Enumerators are assigned from 0
  Up, // (enum member) Direction.Up = 0
  Down, // (enum member) Direction.Down = 1
  // It can be assigned manually, and the following items will be incremented
  Left = 10.// (enum member) Direction.Left = 10
  Right, // (enum member) Direction.Right = 11
}

console.log(Direction.Up); / / 0
console.log(Direction[0]); // Up
Copy the code

Compiled js:

var Direction;
(function (Direction) {
    // Implement bidirectional assignment
    Direction[Direction["Up"] = 0] = "Up";
    Direction[Direction["Down"] = 1] = "Down";
    Direction[Direction["Left"] = 10] = "Left";
    Direction[Direction["Right"] = 11] = "Right";
})(Direction || (Direction = {}));
console.log(Direction.Up);
console.log(Direction[0]); 
Copy the code

String enumeration:

String enumeration, used for string comparisons
enum Direction {
  Up = 'UP'.// (enum member) Direction.Up = "UP"
  Down = 'DOWN',
  Left = 'LEFT',
  Right = 'RIGHT',}const value = 'UP'

if (value === Direction.Up) {
  console.log('go up! ')}Copy the code
var Direction;
(function (Direction) {
    Direction["Up"] = "UP";
    Direction["Down"] = "DOWN";
    Direction["Left"] = "LEFT";
    Direction["Right"] = "RIGHT";
})(Direction || (Direction = {}));
var value = 'UP';
if (value === Direction.Up) {
    console.log('go up! ');
}
Copy the code

Constant enumeration:

Constant enumerations can improve performance, as the values of the enumerations are compiled directly into the results. Constant enumerations inline any use of enumerations and do not compile the enumerations to JS.

Only const numbers can be enumerated, not computed numbers.

// Constant enumeration to improve performance
const enum Direction {
  Up = 'UP',
  Down = 'DOWN',
  Left = 'LEFT',
  Right = 'RIGHT',}const value = 'UP'

if (value === Direction.Up) {
  console.log('go up! ')}Copy the code
var value = 'UP';
if (value === "UP" /* Up */) {
    console.log('go up! ');
}
Copy the code

Generics generic

Usage of generics

First let’s define a function that returns the argument passed in:

function echo(arg) {
  return arg;
}

const result = echo(123); // const result: any
Copy the code

Result is of type any. To make echo’s return value equal and exact to the value passed in, we can use generics.

Generics do not specify types in advance when defining functions, interfaces, and classes, but when they are used.

function echo<T> (arg: T) :T {
  return arg;
}

const result = echo('str'); // const result: "STR", type assertion string
Copy the code
// Swap the contents of two items in a tuple
function swap<T.U> (tuple: [T, U]) :U.T] {
  return [tuple[1], tuple[0]]}const result2 = swap(['string'.123]) // [123, 'string']
Copy the code

Constraints of generic

If we wanted a function to print the length of an array or string, it would be wrong to write:

function echoWithArr<T> (arg: T) :T {
  console.log(arg.length); // Attribute "length" does not exist on type "T".
  return arg
}

function echoWithArr2<T> (arg: T[]) :T[] { // Cannot pass string
  console.log(arg.length);
  return arg
}
Copy the code

We use the extends inheritance interface to constrain generics:

interface IWithLength {
  length: number
}

// Uses extends to constrain the passed generic by specifying that it must have a length attribute
function echoWithLength<T extends IWithLength> (arg: T) :T {
  console.log(arg.length)
  return arg
}

const str = echoWithLength('str')
const obj = echoWithLength({ length: 10.width: 10 })
const arr2 = echoWithLength([1.2.3])
Copy the code

Again, the duck type concept is used as long as the argument has the length attribute.

Application in classes and interfaces

/ / class
class Queue<T> {
  private data = [];
  push(item: T) {
    return this.data.push(item)
  }
  pop(): T {
    return this.data.shift()
  }
}
const queue = new Queue<number>()
queue.push(1)
console.log(queue.pop().toFixed())

/ / interface
interface KeyPair<T, U> {
  key: T
  value: U
}
let kp1: KeyPair<number.string> = { key: 1.value: "string" }
let kp2: KeyPair<string.number> = { key: 'str'.value: 2 }

let arr: number[] = [1.2.3]
// Use generics to declare types
let arr2: Array<number> = [1.2.3]
Copy the code

Type the alias

A type alias is used to define a new name for a type, which is different from interface.

// type aliase Type alias
let sum: (x: number, y: number) = > number;
const result = sum(1.2);

// Create a type alias for the function
type PlusType = (x: number, y: number) = > number;
let sum2: PlusType;
const result2 = sum2(2.3);

// Create a type alias for the object
type Person = { name: string.age: number }
var Jack: Person = { name: "Jack".age: 18 }

// Create a type alias for the union type
type StrOrNumber = string | number;
let result3: StrOrNumber = '123';
result3 = 123;
Copy the code

Type defines an alias for a type, which can be used when crossover or union is needed. Interfaces define unique types, which are used when extends and implements are needed.

literal

Literals can represent not only values but also types, literal types.

// A literal type cannot be assigned to anything other than a type
let str: 'name' = 'name';
// str = 'name1'; Type "name1" cannot be assigned to type "name".
const number: 1 = 1;

// The type alias of the literal type
type Directions = 'Up' | 'Down' | 'Left' | 'Right';
let toWhere: Directions = 'Left';
Copy the code

Cross type

Cross typing is merging multiple types into one type.

// The type alias of the crossover type
interface IName {
  name: string
}
type IPerson = IName & { age: number };
let person: IPerson = { name: '123'.age: 123 };
Copy the code

Declaration file

One way to do this with jQuery is to import it directly in HTML with script tags, and then when you use it in TS, TSC has no way of knowing what jQuery is when you use it directly in TS.

jQuery('#id') // can not find the name "jQuery".
Copy the code

Use the DECLARE keyword to tell TSC that the jQuery variable has been defined elsewhere

declare var jQuery: (selector: string) = > any;
jQuery('#id')
Copy the code

Declarations are generally placed in.d.ts files to indicate that the file has a type declaration for TS:

// jQuery.d.ts
declare var jQuery: (selector: string) = > any;
Copy the code

Declare does not define the implementation of a variable, only its type. Used for type checking only.

After that, there will be corresponding code completion and interface prompts when used in other files. Ts parses all ts files in a project. When.d.ts files are placed in a project, all project files have their corresponding type definitions.

When using a third party library, we can use the declaration file of the third party without having to declare it manually.

For example, use the following command to install the jQuery type file:

npm install --save @types/jquery
Copy the code

@types indicates that the file has only type definitions and no concrete implementation.

You can search for the corresponding third party declaration file at the following url:

  • @types Library of official declaration files

  • @types searches the declaration library

Many libraries now come with their own type definitions in the source code, in which case you can just install the source file.

Such as:

npm install --save redux
Copy the code

We can see that node_modules\redux\index.d.ts is the type declaration file.

Built-in types

There are many standard built-in objects in JavaScript. Standard built-in objects are objects that exist in the global scope according to the standard (ECMA, DOM, etc.).

// global object
const a: Array<number> = [1.2.3];
const date: Date = new Date(a); date.getTime();const reg = /abc/;
reg.test("a");

// Unlike other global objects, Math is not a constructor. All properties and methods of Math are static.
Math.pow(2.2);
Copy the code

You can see that these types are defined in multiple places in different files, but they are all part of the internal definition and then merged according to different versions or functions. Multiple definitions of an interface or class are merged together. These files typically start with lib and end with d.ts, indicating that this is a built-in object type.

// DOM and BOM standard objects
// Document object, which returns an HTMLElement
let body: HTMLElement = document.body;
// The document query method returns a nodeList type
let allLis = document.querySelectorAll('li');

// In the callback function, the e event object here also automatically gets the mouseEvent type because of type inference. Since clicking is a mouse event, we can now conveniently use the methods and properties above E.
document.addEventListener('click'.(e) = > {
  e.preventDefault()
})
Copy the code

Tool type

Typescript also provides several functional and helpful types. These types, which are not visible in JS, are called utility types and provide some neat and convenient functionality.

// utility types
// partial, which makes all incoming types optional
interface IPerson {
  name: string
  age: number
}

let Joe: IPerson = { name: 'Joe'.age: 20 }
type IPartial = Partial<IPerson>
let Joe2: IPartial = {}

Omit, which may Omit an attribute of the incoming type
type IOmit = Omit<IPerson, 'name'>
let Joe3: IOmit = { age: 20 }
Copy the code