A blog to get you started with TypeScript

Using TypeScript is to standardize the development environment, but in the real runtime environment, TypeScript does not actually play any restrictive role.

1. Installation

1. Install TypeScript

npm install typescript -g

After the installation is complete, enter the tsc command in the console to check whether the installation is successful. If a lot of English comes out, it means you have installed it.
Insert picture description here
Now we can write typescript on our computer, but if we want to run a typescript file, We need to use the tsc command to compile the .ts file into a .js file before running the code.

tsc 文件名.ts
node 文件名.js

This is very inefficient for our development, but we can use ts-node to directly execute the typescript file and adjust the intermediate js conversion process.

2. Install ts-node

npm install -g ts-node

After that, we can use the ts-node command to directly execute the ts file

ts-node 文件名.ts

Two, type annotation

We all know that JavaScript is a weakly typed language. Weakly typed languages ​​are not good for our standardized development process. Type annotations are a solution proposed by TypeScript to strengthen language types. Therefore, TypeScript is also a strongly typed language.
For example, if we define a variable age to be of type number, then we cannot attach a value of another type to it.

let age: number;
age = 123;

As shown in the above example, the type annotation in TypeScript is to use the ":" keyword, and the declaration can be completed by: + data type

type of data Key words
String string
Number number
Boolean boolean
Void void
Any any
Undefined undefined
Null null

1. Array type annotation

Uniform type in array

const arr: number[] = [1, 2, 3];

The types in the array are not uniform

const arr: (number | string)[] = [1, "string", 2];

Object array

const student: { name: string, age: number }[] = [
  { name: "小白", age: 21 },
  { name: "小黑", age: 18 },
];

2. The use of tuples

The lack of array

When we are using an array to process a business, if the order of the elements in the array is changed, then our business logic will have an error, but the type annotation of the array will not report an error. At this time, we will use the tuple type Comment (type constraint).

// 如果数组中的元素顺序发生变化,数组的类型注释不报错,存在开发隐患
const beauty1: (string | number)[] = ["A", "student", 18]
const beauty2: (string | number)[] = ["A", 18, "student"]

// 使用元组中的类型约束可以解决此隐患
const beauties1: [string, string, number] = ["A", "student", 18]
const beauties2: [string, string, number] = ["A", 18, "student"]    //报错!

Insert picture description here

Three, the use of Interface

1. The basic application of the interface

For the simple application of the interface, let's take an example directly. For example, let's take a student as an example.

// 创建接口
interface Student {
    name: string;
    age: number;
    exam?: number;  //非必须属性在“:”前加上“?”即可
    [propname: string]: any;    //此接口允许添加新的属性
}
// 接口应用实例
const getStudent = (student: Student) => {
    console.log("名字:" + student.name)
    console.log("年龄:" + student.age)
    // 做一个小判断,如果有成绩则输出成绩,没有成绩则输出提示
    student.exam ? console.log("成绩" + student.exam) : console.log("此人无成绩")
}
// 数据
const xiaobai = {name: "小白", age: 21, exam: 90}
const xiaohei = {name: "小黑", age: 18}
// 以传值的形式调用方法
getStudent(xiaobai)
getStudent(xiaohei)

Insert picture description here

2. Methods in the interface

Based on the above example, if we want to store a method work() in the Student interface , then we can directly declare the method in the interface and constrain its return value type.

interface Student {
    name: string;
    age: number;
    exam?: number;  //非必须属性在“:”前加上“?”即可
    [propname: string]: any;    //此接口允许添加新的属性
    work(): string;     //声明方法的返回值类型为string
}

After declaring the method in the interface, we then perfect the method in the actual object for later use.

const xiaobai = {
    name: "小白", age: 21, exam: 90,
    work() {
        return "学习就是我的工作"
    }
}
const getStudent = (student: Student) => {
    console.log("名字:" + student.name)
    console.log("年龄:" + student.age)
    // 做一个小判断,如果有成绩则输出成绩,没有成绩则输出提示
    student.exam ? console.log("成绩" + student.exam) : console.log("此人无成绩")
    console.log(student.work())
}

3. The realization of the class to the interface in the interface

When we implement the class, remember to write all of the class, otherwise an error will be reported

class xinsheng implements Student {
    name = "小白";
    age = 21;
    work() {
        return "学习就是我的工作"
    }
}

4. Inheritance between interfaces

The Student interface can be used as a basis. If we need a new method based on the Student interface, such as the monitor interface, in which there is a special method in the Monitor to collect the job shouzuoye, then we can implement it like this:

interface Monitor extends Student {
    shouzuoye(): string;
}

Specific examples:

interface Student {
    name: string;
    age: number;
    exam?: number;  //非必须属性在“:”前加上“?”即可
    [propname: string]: any;    //此接口允许添加新的属性
    work(): string;     //声明方法的返回值类型为string
}
// 接口的继承
interface Monitor extends Student {
    shouzuoye(): string;
}
// 接口应用实例
const monitor = (teacher: Monitor) => {
    console.log("名字:" + teacher.name)
    console.log("年龄:" + teacher.age)
    // 做一个小判断,如果有成绩则输出成绩,没有成绩则输出提示
    teacher.exam ? console.log("成绩" + teacher.exam) : console.log("此人无成绩")
    console.log(teacher.work())
    console.log(teacher.shouzuoye())
}
const xiaohei = {
    name: "小黑", age: 18,
    work() {
        return "学习就是我的工作"
    },
    shouzuoye(){
        return "大家把作业交给我"
    }
}
// 以传值的形式调用方法
monitor(xiaohei)

Insert picture description here

Fourth, the use of classes

The concept of classes in typescript is basically the same as in java and es6, there is no difference, the above example.

1. Definition and use of class

class Person {
    name = "小黑";
    age = 18;
    say() {
        return "我叫" + this.name
    }
}
const p = new Person();
console.log(p.say());

2. Class inheritance

The subclass inherits all the properties and methods of the parent class and can be called directly.

class Student extends Person{
    work(){
        return "淦!我是学生,我得学习。"
    }
}
const S = new Student();
console.log(S.say())
console.log(S.work())

Insert picture description here

3. Class rewriting and the use of super keyword

The subclass can override the method in the parent class. The writing method is to rewrite the method in the parent class. If we need to call the properties in the parent class, then we can call it through the super keyword.

class Student extends Person{
    work(){
        return "淦!我是学生,我得学习。"
    }
    // 重写父类中的say()方法
    say(){
        return super.say() + "很高兴认识你!"
    }
}
const S = new Student();
console.log(S.say())
console.log(S.work())

Insert picture description here

4. Class access type and read-only attributes

The access types of the class are public , private , protected

public

Typescript default access type, if you do not declare the access type when writing code, then typescript will default to the public type.
The public access type can be used inside and outside the class. For example, if we declare a variable inside the class, we can directly call the variable outside the class, or modify this variable.

class Person{
    public name:string;
    public say(){
        console.log(this.name)
    }
}
const p = new Person();
p.say() //第一次
p.name = "小白"
p.say() //第二次

The two output results indicate that the internal variables of the class have been modified by external operations.
Insert picture description here

private

The private type is just the opposite of the public above. It can be understood that as long as the braces of the class are out, no operation can directly call him (note that this is a direct call, and later we will have a method to manipulate the private type). I will show you an example.

protected

Protected type. This type is similar to private. It cannot be operated directly after the braces, but protected allows to be operated upon inheritance

class Person{
    protected name:string;
    public say(){
        console.log(this.name)
    }
}
class Student extends Person{
    name = "小黑";
    sayHello(){
        console.log(this.name)
    }
}
const p = new Student();
p.say()
p.sayHello()

Insert picture description here

Readonly attribute

When declaring a variable in a class, you can define the type of the variable. One of the attributes is called readonly. The variable with this attribute will report an error when trying to change its value.

class Person{
	public readonly name: string;
}

5. Class constructor

Ordinary constructor

There is a constructor method in the typescript class , which is our constructor. We can use this method to initialize the class, and the constructor in typescript is very convenient to write, as follows:

class Person {
    constructor(private name: string, public age: number) { }
}
const p = new Person("小黑", 21)
// console.log(p.name);     //这里记得name是私有变量,外部不能直接调用
console.log(p.age)

Subclass constructor

The constructor of the subclass is special. Since we have performed an inheritance extends operation, we must use super() when writing the constructor in the subclass , otherwise typescript will report an error.

class Student extends Person {
    constructor(private exam: number) { 
        super("小白",18);
    }
}

6. Class setter and getter

In the development process, in order to ensure the security of the data, we often define the data as private. If we want to call it, we will use the setter() method and getter() method or constructor method.

class Person {
    constructor(private name: string, private age: number) { }
    get getName() {
        return this.name
    }
    set setName(name: string) {
        this.name = name
    }
    get getAge() {
        return this.age
    }
    set setAge(age: number) {
        this.age = age
    }
}
const p = new Person("小黑", 21)
p.setName = "小白"
console.log(p.getName)

Insert picture description here

7. Use of abstract classes

Abstract class abstract energy introduced to facilitate the preparation of our class specification, the examples:
For example, we need to be reported out of school themselves that unit (class) is.

abstract class School{
    // 抽象类中的方法都需要加上abstract关键字,表示抽象方法
    abstract baobei()
}
class Student extends School{
    // 继承了抽象方法的类都必须对父类中的抽象方法进行具体化,具体跟类的重写是一样的
    baobei(){
        console.log("我是学生,是xx班的")
    }
}

5. Joint Type and Type Protection

1. Joint type

When one of our methods can accept multiple types of parameters (parameter), then the union type is used at this time .

class Student {
    name: string;
    jiaozuoye() { };
}
class Teacher {
    name: string;
    gaizuoye() { };
}
function f(parameter: Student | Teacher) { }

2. Type protection

However, there is another problem that comes with the union type. If there are two different methods in Student and Teacher, how can parameters of different types determine whether there is a special method that inherits the type? To solve this problem, we introduced the concept of type protection .

as syntax

As is also called type assertion. As is equivalent to artificial judgment. For example, a person's name (name attribute) is called "student", then we judge that he is a student and let him call the student's method jiaozuoye(). The specific operation is as follows.

function f(parameter: Student | Teacher) {
    if(parameter.name == "学生"){
        (parameter as Student).jiaozuoye();
    }
}

in syntax

The in grammar is easier to understand. For example, the difference between our Student and Teacher lies in the difference between the method of handing in homework and changing the homework. If the parameter has the function of handing in homework, then we judge him as Student, otherwise judge him as Teacher. When you can use in syntax.

function f(parameter: Student | Teacher) {
    if("jiaozuoye" in parameter){
        parameter.jiaozuoye();
    }else{
        parameter.gaizuoye();
    }
}

typeof syntax

In the above example, the parameters are all custom types. What is our type protection strategy for common types? Give a new example

function f(parameter1: string | number, parameter2: string | number) {
//使用typeof进行类型判断
  if (typeof parameter1 === "string" || typeof parameter2 === "string") {
  //字符串拼接
    return `${first}${second}`;
  }
  return first + second;
}

instanceof syntax

The syntax of instanceof and typeof is very similar, but instanceof can only be used to protect the class .

// 我们先定义一个类,作为我们类型保护的基础
class NumberObj {
    count: number;
}
// 实现一个相加的方法
function f(first: object | NumberObj, second: object | NumberObj) {
    // 运用instanceof语句对类型进行判断
    if (first instanceof NumberObj && second instanceof NumberObj) {
        return first.count + second.count;
    }
    return 0;
}

Six, generic

For generics in TypeScript, you can understand it as a parameterized type , and encapsulate the type of each parameter into the form of a parameter, and this encapsulation method is generic.

1. Function generics

If we want to write a function that receives two parameters, both of these parameters may be of string type or both of number type, and finally do the splicing operation.
For this function, in fact, it can be realized through the above joint type and type protection, but let's analyze the conditions of this function, "These two parameters may be string type or both number type" , think about it, we can Can't you directly tell the parameter type passed in this function when you call it? The answer is yes, generics can achieve this function.

function f<T>(one: T, two: T) {
    return `${one}${two}`
}
f<string>("ok", "fine")

One more mention here. Because TypeScript has type inference capabilities, we don't even need to write generic parameters when calling functions, such as this:

f("ok", "fine")

Of course, we can also define multiple generics.

function f<T, P>(one: T, two: P) {
    return `${one}${two}`
}
f<string, number>("ok", 2)

2. Generic type

Initialize the generic type of the class

Create a class, and write the constructor by the way, with two parameters:

class Student {
    constructor(private name: string, private age: number) { }
}

Parameterize the type of the parameter, realize the generic initialization of the class, and then realize a simple call.

class Student<T, P> {
    constructor(private name: T, private age: P) { }
}
const stu = new Student<string, number>("小白", 21)

Generic inheritance

Following the Student example above, there is now a data structure like this: each Student comes from a Person interface, which has a NAME attribute (string type), and now we need to take out the NAME in a Student object.
First, let's improve the interface and getter functions:

interface Person {
    NAME: string
}
class Student<T> {
    constructor(private name: T) { }
    get getName() {
        return this.name
    }
}

The current interface Person and Student classes are still not related. Next, we use generic inheritance to pass the name in Person to the name in Student. When you understand this, pay attention to the case of the two names, lowercase Is defined in the class, the uppercase is the interface passed to the class .

interface Person {
    NAME: string
}
class Student<T extends Person> {
    constructor(private name: T) { }
    get getName() {
        return this.name.NAME
    }
}

Finally call it.

const stu = new Student({ NAME: "小白" })

If you observe carefully, we will find that when we pass the constructor, we pass in an object directly , with braces. The reason is actually very simple. We can think of Person as a description of the object to be passed in. This description is passed to the name attribute in Student through the extends statement. Finally, when we initialize the object, what we seem to initialize is An object, but what we initialize is the name in the constructor.
At first I saw this place for a long time, but finally I wrote an example based on someone else's code, and after reading it several times, I found that I could understand it.

Guess you like

Origin blog.csdn.net/qq_43592084/article/details/109459409