preface

As a newbie in the workplace, I came to the company and found that everyone did not use the original JS, and all the front-end code was written in TypeScript, so I learned TS in a hurry. Here I share my learning notes, hoping to help some beginners like me!!

1. Development environment construction

(1) Use brew tool to download and install Node

Note: It is best not to download Node directly from the official website for installation, which will cause many uninstallation residual brew installation methods:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
Copy the code

(2) Install node and YARN

Yarn is used as a tool similar to NPM. You can also use NPM

Brew to install Node, run the following command:

brew install node
Copy the code

Install TypeScript

Command line input:

yarn global add typescript
Copy the code

2. Compile the TS file

Go to the file directory and run the TSC ***. Ts command. At this time, a JS file with the same name will be generated in this folder. (Use an online compilation tool if you want to practice on your own)

3. Types of TS

(1) Specify the variable type

Syntax for declaring a variable and specifying its type: let a: type

When a variable has a type declared, it can only be assigned a value of that type (any and unknown are special, as described below) :

let a: number; a = 10; A = 'STR' // An error is reported when assigning a string to aCopy the code

If the variable declaration and assignment are simultaneous (for example, let a = 123), TS can automatically detect the type based on the assigned value and can only change the variable value to the same type in the future.

(2) SUMMARY of TS data types

  • Number: any number

    let a: number = 1

  • String: Any character string

    let str: string = ‘hello’

  • Boolean: Indicates a Boolean value

    let isInteresting: boolean = true

  • Any: Indicates any type

    Let value: any = 'showee' value = 100 let num: Boolean = value let obj: any = {} obj.getname (Copy the code

A variable of type any can obtain any of its attributes and methods. When the type of a variable is set to any, type detection for TS of the variable is disabled. Therefore, use of type any is not recommended.

If you declare a variable without specifying a type, the TS parser automatically determines the type of the variable to be any, as shown below:

let d; D = 10; d = 10; D = 'hello'; D = true; / / is not an errorCopy the code
  • Unknown: Indicates any of type safety

Indicates that the type of a variable is unknown, which means that the variable could be any type of value, and that the value could come from dynamic content.

Let value: unknown = 'showee' value = 100 let num: Boolean = value! Let obj: unknown = {getName: function() {}} obj.getname ()Copy the code

We can narrow the type range of variables by using type guards (e.g., typeof)

Let num: number if (typeof value === 'number') {num = valueCopy the code

Or a type assertion can be used to tell the parser the actual type of a variable

let e: unkown; let s: string; s = e as string; S = <string>e; // < type > variableCopy the code
  • Void: has no value (or undefined). Used to set functions that do not return a value

    function fn(): void{ return; }

  • Never: cannot be any value. It is used to set the function not to return a result

    function error(message: string): never { throw new Error(message); // The function does not return a value}

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

  • – object: indicates any JS object

    let obj: object = { name: ‘showee’ }

    Let obj1: {name: string, age? : number}; // Can be used? To represent the optional property obj1 = {name: ‘showee’}

    let obj2: {name: string, [propName: string]:any}; // [propName: string]:any indicates that any type of attribute can be added in addition to name

  • Object: Object and Object are case and case only. Object can also represent numbers, strings, booleans and other basic types (but not Null and Undefined).

    const obj: Object = { name: ‘showee’ } const obj: Object = ‘showee’ const obj: Object = 100 const obj: Object = true

    Const obj: {} = {name: ‘akara’} const obj: {} = {name: ‘akara’

It is usually suggested to use object instead of object

  • Array: any JS array
Let arr: number[] = [1, 2, 3] let arr: Array<number> = [1, 2, 3]Copy the code
  • Tuple: tuple, TS new type, fixed length array

    let person: [string, number] = [‘showee’, 3]

  • Enum: enumeration. A new type is added in TS

    enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat};

    console.log(Days[“Sun”] === 0); // true console.log(Days[“Mon”] === 1); // true console.log(Days[“Tue”] === 2); // true console.log(Days[“Sat”] === 6); // true

    console.log(Days[0] === “Sun”); // true console.log(Days[1] === “Mon”); // true console.log(Days[2] === “Tue”); // true console.log(Days[6] === “Sat”); // true

  • Literal type: The value of a constraint variable is the value of that literal

    // String literals let STR: ‘small’ = ‘large’

    // Let num: 1 = 1

    // Boolean literals let boo: true = true

Note that variables declared with let and const are of different types, as follows:

let name = 'aka' // string
const name = 'aka' // 'aka' 
Copy the code

4, functions,

(1) Parameters

Optional and default arguments: TS functions are strict about the length of arguments. Indicates an optional parameter, or you can use the default value:

Function A(name: string, age? :number): string | undefined { return name; } function B(name: string = 'showee'): string { return name; }Copy the code

Residual arguments: When you need to manipulate more than one argument at a time, or you don’t know how many arguments will be passed in, you can collect all the arguments into a single variable

function buildName(firstName: string, ... restOfName: string[]) { return firstName + " " + restOfName.join(" "); } let employeeName = buildName("xiao", "ke", "ai");Copy the code

(2) Anonymous function

The types of parameters are automatically derived in anonymous functions

Let arr = [1, 2, 3] arr.foreach (item => console.log(item)Copy the code

(3) this

There may be several types of this in object literals:

If this parameter is specified in the method display, this has the type of that parameter

let bar = {
  x: 'hello',
  f(this: { message: string }) {
    this; // { message: string }
  }
};
Copy the code

Otherwise, if the method is contextually typed by a signature with the this parameter, this has the type of that parameter

let foo = {
  x: 'hello',
  f(n: number) {
    this; // { x: string, f(n: number): void }
  }
};
Copy the code

Otherwise, if the –noImplicitThis option is enabled and the object literal contains the context type typed by ThisType, this has type T

Otherwise, if the –noImplicitThis option is enabled and the object literal does not contain the context type typed by ThisType, then this is of type that context type

Otherwise, this has the type of the object literal if the –noImplicitThis option is enabled

Otherwise, this is of type any

(4) Overload

Provide multiple function type definitions for the same function to override the function. The compiler will process the function calls based on this list. Here is an example from the official website

let suits = ["hearts", "spades", "clubs", "diamonds"];

function pickCard(x: {suit: string; card: number; }[]): number;
function pickCard(x: number): {suit: string; card: number; };
function pickCard(x): any {
    // Check to see if we're working with an object/array
    // if so, they gave us the deck and we'll pick the card
    if (typeof x == "object") {
        let pickedCard = Math.floor(Math.random() * x.length);
        return pickedCard;
    }
    // Otherwise just let them pick the card
    else if (typeof x == "number") {
        let pickedSuit = Math.floor(x / 13);
        return { suit: suits[pickedSuit], card: x % 13 };
    }
}

let myDeck = [{ suit: "diamonds", card: 2 }, { suit: "spades", card: 10 }, { suit: "hearts", card: 4 }];
let pickedCard1 = myDeck[pickCard(myDeck)];
console.log("card: " + pickedCard1.card + " of " + pickedCard1.suit);

let pickedCard2 = pickCard(15);
console.log("card: " + pickedCard2.card + " of " + pickedCard2.suit);
Copy the code

In order for the compiler to choose the right type of check, it is similar to the processing flow in JavaScript. It looks up the overload list and tries to use the first overload definition. Use this if it matches. Therefore, when defining overloads, always put the most precise definition first.

5, class,

(1) Definition and use

Class Person{// Define the instance attribute name: string; age: number; Readonly ID: string = 'sfijper' // Static gender: string = 'female'; constructor(name: string, age: number) { this.name = name; SayHi () {return 'Hi!'; sayHi() {return 'Hi! I am ${this.name},I am ${this.age} years old` } } const xiaohong = new Person('xiahong', 3); Console. log(person.gender) // static attribute access method xiaohong.id = 'sofj' // error, read-only attribute cannot change console.log(xiaohong.sayhi ()) // "Hi! I am xiahong,I am 3 years old"Copy the code

(2) Inheritance

After using inheritance, subclasses can all the methods and properties of a parent class, through the way of inheritance can be multiple classes of the communist party of China some code written in a parent class, so you just need to write a let all subclasses have properties and methods of the parent class, at the same time and can be classified in a subclass to add some of the properties and methods. Overriding a method in a subclass by adding the same method as its parent class is called method rewriting.

Class Person{// Define the instance attribute name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age } sayHi() { console.log(`Hi! I am ${this.name},I am ${this.age} years old ')}} console.log('lalalalala... SayHi () {console.log('I am a cool boy')}} const xiaohong = new Person('xiaohong', 3); xiaohong.sayHi(); // "Hi! I am xiaohong,I am 3 years old" const boy = new Boy('xiaoshuai', 3); boy.sing(); // "lalalalala..." boy.sayHi(); // "I am a cool boy"Copy the code

The super keyword: In the methods of a class, super represents the parent of the current subclass. If you need to write a constructor in a subclass, you must call the parent constructor in the subclass constructor using super()

class Person{ name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age } sayHi() { console.log(`Hi! I am ${this.name},I am ${this.age} years old`) } } class Boy extends Person{ id: string constructor(name: string, age: number, id: string) { super(name, age); this.id = id; } sayHi() { super.sayHi(); console.log(`Hi! I am ${this.name},I am ${this.age} years old,my id is ${this.id}`) } } const xiaohong = new Person('xiaohong', 3); const boy = new Boy('xiaoshuai', 3, 'abcdefg'); xiaohong.sayHi(); boy.sayHi();Copy the code

(3) Abstract classes

Classes that begin with abstract are abstract classes. Abstract classes are not much different from other classes except that they cannot be used to create objects, but they can be inherited. (Usually, we create abstract classes that are specifically designed to be inherited, to be used as parent classes.)

Abstract methods can be added to an abstract class. Abstract methods start with abstract and have no method body. Abstract methods can only be defined in abstract classes, and subclasses must override abstract methods.

abstract class Person{ name: string; constructor(name: string) { this.name = name; } abstract sayHi(): void; } class Boy extends Person{sayHi() {console.log(' I am a Boy ')}} const Person = new Person(); // error Cannot create an instance of an abstract class. Const boy = new boy ('xiaoshuai'); boy.sayHi();Copy the code

(4) Interface

Interfaces are used to define the structure of a class. They define what properties and methods a class should contain. Interfaces can also be used as type declarations.

interface myInterface{ name: string; age: number; } // When defining two interfaces with the same name as =, the effect is merged. } const obj: myInterface = { name: 'showee', age: 3, gender: 'male' }Copy the code

None of the attributes in the interface can have real values, and all of the methods are abstract.

When you define a class, you can make it implement an interface.

interface myInterface{
    name: string;
    age: number;

    say(): void;
}

class myClass implements myInterface{
    name: string;
    age: number;
    
    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }
    
    say() {
        console.log('hello')
    }
}
Copy the code

(5) Encapsulation of attributes

TypeScript has three access modifiers, public, private, and protected

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

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

  • A property or method modified by private is private and cannot be accessed or modified outside the class in which it is declared. We can add methods to a class that make them accessible and modified outside the class (getters and setters, called property accessors).

    class Person{ private _name: string;

    constructor(name: string) { this._name = name; Get name() {return this._name} set name(value: string) {this._name = value}Copy the code

    }

    const person = new Person(‘showee’); console.log(person.name); // ‘showee’ person.name = ‘erbao’; console.log(person.name); // ‘erbao’

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

    class Person{ protected name: string;

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

    }

    class Boy extends Person{ test() { console.log(this.name) } }

    const xiaohong = new Person(‘xiaohong’); const boy = new Boy(‘xiaoshuai’); Console. log(xiaohong.name) // Error Property ‘name’ is protected and only accessible within class ‘Person’ and its subclasses. boy.test(); / / ‘xiaoshuai’

6, generics

When defining a function or class, you can use generics if the type is ambiguous. You can specify more than one type at a time

function fn<T>(a: T): T{ return a; } // Let res1 = fn(10); // let res2 = fn<string>('hello'); // Specify the generic console.log(typeof res1, typeof res2); // Use generic interface Inter{length: number; } function fn1<T extends Inter>(a: T): number{return a.length; } // Use the generic class MyClass{name: T; constructor(name: T) { this.name = name; } } const myClass = new MyClass<string>('showee');Copy the code

7. Type manipulation

(1) Joint type

The union type indicates that the value can be one of many types.

let value: string | number;
value = 'showee';
value = 123;
Copy the code

When we are not sure 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{ return something.length; } / / here will be an error, because the length is not a string and the number of attributes, the function get string (something: string | number) : string{ return something.toString(); } // There is no error because toString is a common property of string and numberCopy the code

(2) Cross type

type a = {
    name: string;
}
type b = {
    age: number;
}
let obj: a & b = {
    name: 'showee',
    age: 0,
}
Copy the code

(3) Type assertion

When you know the type of a value very well, you can tell the compiler what you think by asserting it. This is somewhat similar to casting in other languages. Type assertions come in two ways

let someValue: any = "this is a string"; let strLength: number = (<string>someValue).length; // Angle bracket syntax let someValue: any = "this is a string"; let strLength: number = (someValue as string).length; / / as syntaxCopy the code

(4) Type protection (Type guard)

Type protection is an expression for an executable runtime check to ensure that the type is within a certain range.

Type protection is similar to property detection in that the main idea is to try to detect properties, methods, or stereotypes to determine how values are handled. There are four main ways to implement type protection

  • typeof

In JS typeof can be used to get the basic typeof a variable, while in TS, type can be obtained

function doSome(x: Number | string) {if typeof (x = = = 'string') {/ / in this block, TypeScript know ` ` x type must be ` string ` console. The log (x.s ubtr (1)); // Error: 'subtr' method does not exist on 'string' console.log(x.substr(1)); // ok } x.substr(1); // Error: no guarantee that 'x' is of type 'string'}Copy the code
  • In the 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); }}

  • Instanceof

    class Foo { foo = 123; common = ‘123’; }

    class Bar { bar = 123; common = ‘123’; }

    function doStuff(arg: Foo | Bar) { if (arg instanceof Foo) { console.log(arg.foo); // ok console.log(arg.bar); // Error } if (arg instanceof Bar) { console.log(arg.foo); // Error console.log(arg.bar); // ok } }

    doStuff(new Foo()); doStuff(new Bar());

  • 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) Type alias

A type alias is used to give a type a new name

type Message = string | string[];

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

(6) keyof

This operator can be used to get all keys of a type whose return type is the union type

interface Person {
  name: string;
  age: number;
  location: string;
}
type K1 = keyof Person; // "name" | "age" | "location"
type K2 = keyof Person[]; // "length" | "push" | "pop" | "concat" | ...
type K3 = keyof { [x: string]: Person }; // string
Copy the code