This is the 26th day of my participation in the August Text Challenge.More challenges in August

The articles

Typescript Notes (1)

The last article introduced typescript’s basic types and a few other things, but this article will document some of the common features of TS.

Types of assertions

A type assertion, in short, is a statement about the type of a variable.

Var times = 2; The Times variable in this statement life is of type Number.

Of course some people say I know ah, I wrote the code myself can I not know? The assertion poem is for TS. Ts uses assertions to help you determine if there is a problem in your code logic, and others can quickly understand the meaning of these variables through type assertions in your code.

In short, type assertion is an awesome feature of TS. It’s like a heifer on a rocket

So how do you use type assertions in typescript?

let sth: any = 'this are sth special here'
Copy the code

Since STH is an arbitrary type, it may or may not have the length attribute, and if we want to read the length attribute, we need to assert that it is a string. There are two approaches, the second of which must be used in TSX

  • let sthLength: number = (<string>sth).length
  • let sthLength2: number = (sth as string).length

Type inference

Writing type assertions for each variable is a huge waste of time, and TS clearly understands this, so IT provides type inference.

The so-called type inference means that when we write code to define a variable, we do not have to specify the type explicitly. Later, TS can automatically change the type of the variable according to the value of the variable. Therefore, type inference requires that the variable must be assigned when it is defined

let myFavoriteNumber = 'seven';
myFavoriteNumber = 7; //error
Copy the code

If there is no assignment at the time of the definition, it is inferred to be of type any regardless of whether there is a subsequent assignment or not and is not typed at all

let myFavoriteNumber;
myFavoriteNumber = 'seven'; //OK
myFavoriteNumber = 7; //ok
Copy the code

The joint type

In many cases, the type of a variable is not necessarily fixed. For example, we often initialize an interval execution:

var timer = null
timer = setTimeout(console.log, 1000)
Copy the code

In view of this situation, TS introduced the concept of joint type, which is used to indicate that the value range of a variable can be one or a set of several types.

let myFavoriteNumber: string | number;
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

function getLength(something: string | number) :number {
    something.length; //error
    something.toString(); //ok
}
Copy the code

In addition, when a variable that has been defined as a union type is assigned, TS will infer a definite type according to the rules of type inference

let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven';
console.log(myFavoriteNumber.length); / / 5
myFavoriteNumber = 7;
console.log(myFavoriteNumber.length); //error
Copy the code

interface

Interface is a description of a thing in essence, there is no concept of object-oriented programming in JS itself, so through the description of the object or function, thus forming a convention on the level of using the object or function.

To distinguish the interface from ordinary variables such as object functions, the interface is capitalized and the shape of the variable must be the same as that of the interface when assigning values.

So, interfaces can be used in three ways:

  • Used to abstract part of a class’s behavior,
  • Also used to describe the Shape of an object, such as a function,
  • It can also be used to mix the two.
interface Person {
    name: string;
    age: number;
}

interface Sum{
    (x:number.y:number) :number
}
let sum:Sum = (a,b) = > { return a+b }
Copy the code

Arbitrary and optional properties

But generally speaking, a defined object is not used the same as its definition, in which case the interface definition can use optional attributes as well as arbitrary attributes.

Are optional attributes used? Arbitrary attributes are represented by []

interfacePerson { age? :string; // Optional attributes
}
interface Animal {
     [propName: string] :string; // An arbitrary attribute
}
Copy the code

Note: If any attribute is defined, the type of both the determined attribute and the optional attribute must be a subset of its type

interface Person {
    [propName: string] :string; // The value type of any attribute is stringage? :number;  //error The number type is not correct because any attribute is defined as string
}
Copy the code

Read-only property

Sometimes we want to define a property in an object that cannot be changed by the outside world. The implication is that the property is read-only, so read-only properties are used here

Read-only property: Readonly can be used to define that a property is read-only and cannot be reassigned

interface Person {
    readonly id: number;
}

let tom: Person = {
    id: 89757
}

tom.id = 1 //error
Copy the code

Interface inheritance

The three basic characteristics of phase objects are inheritance, encapsulation and polymorphism.

In order to better support JS object-oriented programming, TS specifies that interfaces can be inherited. Inheritance is represented by extends.

Let’s say we have a base class called shape, and that shape has a color property

interface Shape {
  color: string
}
Copy the code

Then we need to implement a quadrilateral interface that inherits the shape base class to get the color property

interface Square extends Shape {
  sideLength: number
}
let square = {} as Square
square.color = 'blue'
square.sideLength = 10
Copy the code

Inheritance can be one-to-many, that is, an interface can inherit from multiple interfaces


interface PenStroke extends Shape, Square{
  width: number
}
Copy the code

An array of class

Array and ordinary arrays, array is only has the attributes of the index and the length of the object, such as document. GetElementsByClass return values

Therefore, class arrays should not be defined as normal arrays, but as interfaces.

Ts has defined interfaces for class arrays, so we can use them directly, such as IArguments, NodeList, HTMLCollection, HTMLElement, etc

function sum() {
    let args: IArguments = arguments;
}

var p:HTMLElement = document.createElement('p')
Copy the code

Built-in objects

Built-in object types include several basic and complex types, as well as Date and Error.

In TypeScript, variables are defined as built-in object types, such as an error

let e: Error = new Error('Error occurred');
Copy the code

Or define a date type

let d: Date = new Date(a);Copy the code

Or regular expressions

let r: RegExp = /[a-z]/;
Copy the code

At the same time, JS also has two very important built-in objects, that is DOM and BOM, I believe that all students who have learned javascrit, are impressed by these two objects.

DOM and BOM provide built-in objects such as Document, HTMLElement, Event, NodeList, etc

let body: HTMLElement = document.body;
let allDiv: NodeList = document.querySelectorAll('div');
document.addEventListener('click'.function(e: MouseEvent) {
  // Do something
})
Copy the code

function

The biggest difference between a function and other variables is that a function has inputs and outputs.

To constrain this in TypeScript, you need to take into account both input and output.

Function constraints provided by TS are also divided into two types, one is function declaration, the other is function expression.

Where, the function declaration is written as follows:

function sum(x: number, y: number) :number {
    return x + y;
}
Copy the code

Function expressions are written slightly differently, because expressions also need to describe declared function variables

let mySum: (x: number, y: number) = > number = function (x: number, y: number) :number {
    return x + y;
};
Copy the code

(x: number, y: number) => number

Note that the => in the function expression above is different from the arrow function in ES6, where the left side of the => represents the constraint on the function’s input and the right side represents the constraint on the function’s output

Of course, this is often confusing to the reader, so TS provides an alternative description

Use interfaces to constrain functions

We can also use interfaces to constrain functions, which we wrote about earlier, which might look a little bit better than expressions

interface MySum {
    (x: number.y: number) :number;
}

let sum: MySum = function(x: number, y: number) {
    return x + y
}
Copy the code

Optional parameters

Sometimes, especially in plug-in encapsulation of methods, some parameters are not mandatory, and if the user does not pass such parameters, we can assign them internally by default

So ts provides optional arguments.

Optional argument: also used in functions? To describe optional parameters, which are placed after required parameters

function buildName(firstName: string, lastName? :string) {
    if (lastName) {
        return firstName + ' ' + lastName;
    } else {
        return firstName + 'Cat'; }}let tomcat = buildName('Tom'.'Cat');
let tom = buildName('Tom');
Copy the code

Parameter Default Value

ES6 adds the use of default values for function arguments (a=1)=>a++

In this case, TS uses the parameter defaults to constrain.

Parameter defaults: TypeScript recognizes parameters with default values as optional, so there is no constraint that 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

Parameter deconstruction assignment

At the same time, TS’s deconstruction of ES6 also provides constraint writing

function push(array: any[], ...items: any[]) {
    items.forEach(function(item) {
        array.push(item);
    });
}

let a = [];
push(a, 1.2.3);
Copy the code

Function overloading

Function overloading: function overloading is a special case of a function. For ease of use, C++ allows several functions of the same name to be declared in the same scope, but the formal arguments (the number, type, or order of the arguments) of these functions must be different. That is, the same function performs different functions.

However, there is no concept of function overloading in javascript, and the function variable declared after will overwrite the previous variable of the same name, so we usually implement pseudo-overloading by judging the parameters

function reverse(x: number) :number;
function reverse(x: string) :string;
function reverse(x: number | string) :number | string {
    if (typeof x === 'number') {
        return Number(x.toString().split(' ').reverse().join(' '));
    } else if (typeof x === 'string') {
        return x.split(' ').reverse().join(' '); }}Copy the code

In the code above, we repeat the function reverse multiple times, the first several times as a function definition, and the last time as a function implementation.

TypeScript matches function definitions first, so multiple function definitions with inclusion relationships need to have the exact definition first

Mixing interfaces and functions

Interfaces can be used to mix classes and functions.

This is because you can define both properties and methods that belong to a class.

interface Counter {
  (start: number) :string
  interval: number
  reset(): void
}

function getCounter() :Counter {
  let counter = (function (start: number) {})as Counter
  counter.interval = 123
  counter.reset = function () {}return counter
}

let c = getCounter()
c(10)
c.reset()
c.interval = 5
Copy the code

class

ES6 provides the concept of classes to make it easier to use object-oriented programming ideas.

Classes can be seen as the most basic units in the program, such as tank battles, tanks can be seen as classes, bullets can be seen as classes, walls can be seen as classes.

So the class itself can define multiple properties and methods. For each property and method, there are additional constraints, such as whether the property is public or private, in addition to its own type constraints.

The modifier

There are many types of modifiers for classes:

The modifier meaning note
public Public property or method Access at will
private Private properties or methods Not accessible from outside, not inheritable
protected A protected property or method Can only be inherited
static Static properties or methods Exists only in the class itself
readonly Read-only property or method Must be initialized at declaration time or in a constructor
abstract Abstract classes or methods Abstract classes cannot be instantiated; abstract methods must be implemented by subclasses

Properties or methods decorated by public are public, can be accessed anywhere, and can be inherited. By default, all properties and methods are public

class Animal {
    public name: string;
    public constructor(name: string) {
        this.name = name; }}let a = new Animal('Jack');
console.log(a.name); // Jack
a.name = 'Tom';
console.log(a.name); // Tom
Copy the code

A property or method modified by private is private, cannot be accessed outside the class in which it is declared, and cannot be inherited

class Animal {
    private name: string;
    public constructor(name: string) {
        this.name = name; }}let a = new Animal('Jack');
console.log(a.name); // error
a.name = 'Tom'; //error

class Cat extends Animal {
    constructor(name) {
        super(name);
        console.log(this.name); //error}}Copy the code

When the constructor’s modifier is private, the class is not allowed to be inherited or instantiated

class Animal {
    public name: string;
    private constructor (name: string) {
        this.name = name; }}class Cat extends Animal { //error
    constructor (name) {
        super(name); }}let a = new Animal('Jack');//error
Copy the code

When the constructor is protected, the class is only allowed to be inherited

class Animal {
    public name: string;
    protected constructor (name: string) {
        this.name = name; }}class Cat extends Animal {
    constructor (name) {
        super(name); }}let a = new Animal('Jack'); //error
Copy the code

Protected attributes or methods are protected, just like private, except that they are accessible in subclasses

class Animal {
    protected name: string;
    public constructor(name: string) {
        this.name = name; }}class Cat extends Animal {
    constructor(name) {
        super(name);
        console.log(this.name); //ok}}Copy the code

Static is a proposal in ES7 that defines static properties that exist on the class itself rather than on an instance of the class

class Animal {
    static num: number = 42;

    constructor() {
        // ...}}console.log(Animal.num); / / 42
Copy the code

Readonly A read-only property that must be initialized at declaration time or in a constructor

class Person {
    readonly age: number
  constructor(public readonly name: string, age: number) {
  	this.name = name
  	this.age = age
  }
}
let a = new Animal('Jack'.25);
console.log(a.name); // Jack
a.name = 'Tom'; //error
a.age = 26; //error
Copy the code

Abstract is used to define abstract classes and their methods. First, abstract classes are not allowed to be instantiated, and second, abstract methods in abstract classes must be implemented by subclasses

abstract class Animal {
    public name: string;
    public constructor(name) {
        this.name = name;
    }
    public abstract sayHi(): void;
}

let a = new Animal('Jack');  //error

class Cat extends Animal {
    public sayHi(): void {    // The inherited class must implement this method
        console.log(`Meow, My name is The ${this.name}`);
    }
    public eat(): void {
        console.log(`The ${this.name} is eating.`); }}let cat = new Cat('Tom');
Copy the code

Accessors: Use getters and setters to change the assignment and read behavior of properties

// Check whether the user password is correct before allowing the user to modify the employee information
class Employee {
  private _fullName: string
  private _passcode: string

  constructor(readonly passcode: string){
    this._passcode = passcode
  }
  get fullName() :string {
    return this._fullName
  }

  set fullName(newName: string) {
    if (this._passcode && this._passcode == 'secret passcode') {
      this._fullName = newName
    }
    else {
      console.log('Error: Unauthorized update of employee! ')}}}let employee = new Employee('secret passcode')
employee.fullName = 'Bob Smith'
if (employee.fullName) {
  console.log(employee.fullName)
}
Copy the code

Interface with the class

Classes are allowed wherever interfaces are allowed

class Point {
  x: number
  y: number
}

interface Point3d extends Point {
  z: number
}

let point3d: Point3d = {x: 1.y: 2.z: 3}
Copy the code

Class implementation interface

Interfaces can be used not only to describe attributes of a class, but also to implement class methods, which are called class-implementation interfaces.

If there are features common to different classes, you can extract them as interfaces using the implements keyword.

For example: door is a class, security door is a subclass of door. If the security door has an alarm function, we can simply add an alarm method to the security door. At this time, if there is another class, car, also has the function of alarm, you can consider the alarm extraction, as an interface, security door and car to achieve it

interface Alarm {
    alert();
}

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

The same class can also implement multiple interfaces, making it possible to add multiple constraints to the class.

interface Alarm {
    alert();
}

interface Light {
    lightOn();
    lightOff();
}

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 class

As mentioned earlier, interfaces can inherit from each other, but interfaces can also inherit from classes.

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

interface Point3d extends Point {
    z: number;
}

let point3d: Point3d = {x: 1.y: 2.z: 3};
Copy the code