Enter the world of TS from 0 to entry

This article has participated in the call for good writing activities, click to view: back end, big front end double track submission, 20,000 yuan prize pool waiting for you to challenge!

As we all know, JS is a weakly typed language with fewer specifications. This can make it hard to spot bugs until the project is live, and once the project is live, bugs are popping up. So, over the past two years, TS has quietly risen.

Monday with a wave of upsurge, also began to enter the world of TS, have to sigh ts static beauty.

The following article will explain some of my summaries of TS introduction. Let’s find out!

What is TypeScript?

1. Type of programming language

Dynamic Typed Languages Statically Typed Langeage
JavaScript C,C++,C#,JAVA

2. What exactly is TypeScript?

  • Typescript, Javascript that scales;

  • Ts transforms JS, a dynamic language that does not care about types, into a static language that cares about types.

  • You can say that TS is a statically typed style type system;

  • Syntax support from ES6 to ES10 and even ESNext;

  • Compatible with all browsers, all kinds of systems, all kinds of servers, completely open source.

Why learn TypeScript?

1. The program is easier to understand

Dynamic languages have problems with the input and output parameter types of functions or methods, and are subject to various constraints, such as manual debugging. So with TS, the code itself solves that problem, ts makes it easier for programs to understand, programs to understand us, and we can do a lot less.

Just like when we talk with others, if we clearly express our logic to each other, the other party will immediately understand us and understand us, we also save effort and do not need a lengthy introduction.

2, more efficient

Ts can jump between different code blocks and definitions, and code can be completed.

At the same time, TS has a rich interface prompt, you can use. To prompt all interface content.

3. Fewer mistakes

Ts can find most errors during programming. This can eliminate some of the more common errors, but also make the following program run more smoothly.

4. Very inclusive

Ts is fully compatible with Javascript, and if you want to introduce third-party libraries like JQuery, you can write separate type files to introduce those libraries.

A little flaw

Compared with JS, TS needs to get used to some norms at the beginning of learning, which will increase the learning cost in the short term. However, the increase of short-term learning cost will reduce many unnecessary mistakes and troubles in the later development, and indirectly bring great benefits for their own development.

This is the end of the chat, let’s enter the world of TS!

Getting started with typescript

How do I install TypeScript

npm install -g typescript 
Copy the code

2. View the version number

tsc -v
Copy the code

Typescript data types

1. Raw data type and Any type

(1) Original data type

// Define a Boolean data
let isDone: boolean = false

// Define a numeric type
let age: number = 20

// Define the string type
let firstName: string = 'monday'
let message: string = `Hello, ${firstName}`

// Define undefind and null types
let u: undefined = undefined
let n: null = null

// Assign undefid to the number
let num: number = undefined

Copy the code

(2) Any type

If we are sometimes unsure what type a data is, we can use the any type. Such as:

// Define data of type any
let notSure: any = 4
notSure = 'maybe a string'
notSure = true

notSure.myName
notSure.getName()

Copy the code

2. Arrays and tuples

(1) Array

// Declare an array of numeric types
// Note: the following array can only pass numbers, passing other types of data will generate an error
let arrOfNumbers: number[] = [1.2.3];
arrOfNumbers.push(3)

function test(){
    //arguments are arrays of classes
    console.log(arguments)}Copy the code

(2) tuples

// Determine the contents and quantity of a tuple
// The first attribute must be of type String and the second attribute of type Number
let user: [String.Number] = ['abc'.13]
Copy the code

3

Interface definition:

  • rightObject the ObjectThe shape of the(shape)To describe;
  • Duck Typing.

Let’s look at a piece of code:

interface Person{
    // readonly Indicates the read-only state
    readonly id: number.name: String.// A question mark is added to indicate whether this parameter is optionalage? :number
}

let monday: Person = {
    id: 1.name: 'monday'.age: 18
}

monday.id = 12323; // If you can't access it, you can't access it
Copy the code

4, Function

Function What is a function?

  • inJSIn, the function is first-class citizen.
  • Functions are like any other type of object. They can be arguments, they can be stored in arrays, they can be returned by another function, they can be assigned to another variable.
  • A function consists of two main parts: input (passing parameters) and output (returning results).

Let’s look at an example:

function add(x: number, y: number, z? :number) :number{
    if(typeof z === 'number') {return x + y + z;
    }else{
        returnx + y; }}let result = add(1.2.3);
console.log(result); / / 6
Copy the code

Using the above function, we can add two or three trees. At this point, it is important to note that optional parameters must not be followed by uncertain parameters, otherwise the program will occur chaos. Such as:

function add(x: number, y: number, z? :number, t: number) :number{
    if(typeof z === 'number') {return x + y + z;
    }else{
        returnx + y; }}Copy the code

T in the code above is definitely not allowed to add, because there is an optional parameter Z in front of it, and then suddenly there is a T, which makes no sense.


So here, let’s say we have a new variable name, called add2. At this point we want to give it a type like add. So what to do about it?

let add2: (x:number, y:number, z? :number) = > number = add
Copy the code

Note that the arrow => above is not an arrow function in ES6, but a method in TS that declares the return value of a function type.

As shown in the above statement, add2 returns a value of type number and sets it equal to add. Also, remember that in TS, everything after: is declared in the declaration type.


So this is kind of redundant, but let’s do the same thing with interface.

In point 3, interface describes the shape of an object, but it is worth noting that interfaces can also describe the shape of functions. Let’s do that in code.

interface ISum {
    (x: number.y: number, z? :number) : number
}

let add2: ISum = add
Copy the code

From the above code, we can see that wrapping the return value of a function in a line with an interface looks much more elegant. Here’s a taste of the power of interfaces, and we’ll talk more about that later.

Type inference, union type, and type assertion

(1) Type inference

Sometimes we assign a value to data without defining its type. How do we know that at this point. What about the type of data?

Such as:

let str = 123
Copy the code

When this happens, the compiler assigns STR directly to the number type. So here’s what we want to do:

let str = 123
str = 'asd' / / complains
Copy the code

Of course it didn’t work out. When first assigned, the compiler already gives STR a number and assumes that STR is of type number. And then we want to assign a string to STR, which is bound to be an error.

(2) Joint type

Sometimes we are not sure about the type of a piece of data, such as whether a piece of data is a number or a string. At this point we can use the union type to do a wave of operations.

let numberOrString: number | string
Copy the code

In this way, we perform associative type operations on the attribute numberOrString that we define.

In general, union types are used in conjunction with type assertions. Let’s talk about type assertions.

(3) Type assertion

1) 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, and sometimes we need to access properties or methods that are specific to one of the types without determining the type. So we specify it as a type by way of type assertion. (This only tricks the TS into trusting the type we specify.)

let str = 123
function getLength(input: string | number) : number{
    // Type assertion for input with as, specify a type for input, then determine if it is not converted
    // Note: Type assertion only does type selection, not conversion
    const str = input as string
    console.log(typeof str)
    if(str.length){
        return str.length
    }else{
        const number = input as number
        return number.toString().length
    }
}
Copy the code

2) By now, you’re starting to feel the magic of type assertions. But this approach felt a little redundant, so we introduced a Type guard. Let’s look at the implementation.

let str = 123
function getLength2(input: string | number) :number{
    if(typeof input === 'string') {return input.length
    }else{
        return input.toString().length
    }
}
Copy the code

Classes in Typescript

In JS, we use constructors and prototype chains to achieve inheritance, while in ES6, there is a class class inheritance method. In typescript, inheritance is much richer. Let’s find out!

1. Class definition

Let’s first look at the definition of a class.

(1) Class

A class defines the abstract nature of everything, including its properties and methods. Such as:

class Animal{
    // The constructor is instantiated at execution time
    constructor(name){
        this.name = name
    }
    run(){
        return `The ${this.name} is running`}}Copy the code

Reading the code above, we can see that a class can be defined by class.

(2) Object

The Object Object is an instance of a class. For example: 🙆♂️

We can think of a class as a blueprint. For example, if a car is a class, it is like a blueprint for building a car. The second one is Object, Object is generated by new, so we have the blueprint of the car in front, now we can create the real car. We can say that a Tesla is an example of a car, and a BMW is another example of a car.

Again, let’s use the example above to derive. Details are as follows:

class Animal{
    // The constructor is instantiated at execution time
    constructor(name){
        this.name = name
    }
    run(){
        return `The ${this.name} is running`}}const snake = new Animal('lily')
console.log(snake.run())
Copy the code

As you can see from the above code, we define a snake that inherits from Animal, so it can use Animal properties and methods.

The output is as follows:

(3) Three main features of OOP

The three main features of object orientation are encapsulation, inheritance and polymorphism.

  • Encapsulation: Hides the operation details of data and exposes only the external interface. In this case, external callers do not need or can not know the details and can only access the object through the external interface.
  • Inheritance: A subclass can inherit from its parent, which has all the characteristics of its parent, as well as some more specific characteristics.
  • Polymorphism:Related different classes generated by inheritance,There can be different responses to the same method. For example, cats and dogs, they can inheritAnimalClass, but they are implemented separatelyrun()Method, in which case, for a particular instance, we don’t need to know if it’s a dog or a cat, we can just call itrun()The program will automatically figure out how to execute the method.

Again, let’s use the code above to derive what inheritance and polymorphism look like.


Inheritance:

class Animal{
    // The constructor is instantiated at execution time
    constructor(name){
        this.name = name
    }
    run(){
        return `The ${this.name} is running`}}const snake = new Animal('lily')
// console.log(snake.run())

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

Copy the code

The output is as follows:

As can be seen from the above, Dog inherits Animal class, and now Dog has the attributes and methods of Animal class. And Xiaoqi instantiates Dog, so it also has Dog properties and methods.


Polymorphism:

class Animal{
    // The constructor is instantiated at execution time
    constructor(name){
        this.name = name
    }
    run(){
        return `The ${this.name} is running`}}const snake = new Animal('lily')
// console.log(snake.run())
//-----------------------------------
class Dog extends Animal{
    bark(){
        return `The ${this.name} is barking`}}const xiaoqi = new Dog('xiaoqi')
console.log(xiaoqi.run())
console.log(xiaoqi.bark())
//-----------------------------------
class Cat extends Animal{
    Static methods do not need to be instantiated, they can be called directly on the class
    static categories = ['mammal']
    constructor(name){
        super(name)
        console.log(this.name)
    }
    run(){
        return `Meow, ` + super.run() 
    }
}
const maomao = new Cat('maomao')
console.log(maomao.run())
// Access static properties directly
// Why static attributes? Consider using static implementations when the definition has little to do with the instance
console.log(Cat.categories)

Copy the code

The output is as follows:

Reading the code, we can find that Xiaoqi inherits the run() method of dog, while Cat inherits the Animal class, but it rewrites the run() method, so the final run() method is the rewritten effect.

So, maomao inherits Cat, and when maomao finally calls run(), it calls the run() method that was overwritten in Cat instead of the Animal run() method.

In this way, although Xiaoqi and Maomao also inherit from Animal class, the results of their calls to run() are independent of each other, thus realizing polymorphism.

Also, we have to pay attention to static properties. As you can see, categories, defined above, use static to define them as static properties. When a variable is defined as a static property, the static method does not need to be instantiated and can be called on the class when it is needed externally.

So the question is, when do we need static properties?

In fact, static methods can be considered when the content of the definition has little to do with the instance. Constants, for example, are basically fixed and do not change, so we can consider using static methods to retrieve them directly.

Classes in Typescript

How does Typescript enhance classes? Typescript typically enhances classes with four modifiers:

The modifier meaning
public The modified property or method is public
private The decorated property or method is private
protected The decorated property or method is protected
readonly You can only read but not write

With these four modifiers, we can manage permissions for class methods and properties. Why do permissions management? Because there is always something we don’t want to expose to external use, we need to manage permissions.

Note that for the protected modifier, only subclasses have access to the properties and methods of the parent class, and no other instances do. Protected is an inheritance. Everything in the parent class is inherited directly from the child and is not accessible to outsiders.

3. Classes and interfaces

(1) What problems are solved

One of the dilemmas of inheritance is that in the object-oriented world, a class can only inherit from another class. Sometimes classes have some common features, but it is difficult to inherit from a parent class using a subclass. So the interface appears.

(2) How to solve it

Classes can implement interfaces using implements. How? You can extract these same features into interfaces and implement them with the implements keyword, which dramatically increases object-oriented flexibility.

(3) Take an example

If we were to use a car and a mobile phone to enable the function of opening a player, we would do this:

class Car{
    switchRadio(trigger: boolean){}}class CellPhone{
    switchRadio(trigger: boolean){}}Copy the code

But it doesn’t look particularly elegant. So you can write an interface that opens the player and implement it with implements. The code is as follows:

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

class Car implements Radio{
    switchRadio(trigger: boolean){}}class CellPhone implements Radio{
    switchRadio(trigger: boolean){}}Copy the code

This enabled Car and CellPhone to turn on the CellPhone player.

Next, we continue to write an interface that can check the battery level. And let the phone not only open the player, but also check the battery. The code is as follows:

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

interface Battery{
    checkBatteryStatus(): void
}
    
class Car implements Radio{
    switchRadio(trigger: boolean){}}class CellPhone implements Radio.Battery{
    switchRadio(trigger: boolean){}checkBatteryStatus(){}}Copy the code

Reading the code, we can see that we are inheriting two interfaces, Radio and Battery, which seems a bit redundant. So we can do this:

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

interface RadioWithBattery extends Radio{
    checkBatteryStatus(): void
}

class Car implements Radio{
    switchRadio(trigger: boolean){}}class CellPhone implements RadioWithBattery{
    switchRadio(trigger: boolean){}checkBatteryStatus(){}}Copy the code

Interface inherits interface through interface, and finally abstracts and verifies the attributes and methods of class with Implement, so as to achieve the purpose of pulling out function.

I believe that through the above simple understanding, you can feel the magic of interface.

Sixth, the enumeration

1. Common enumeration

Enumerations are often used when we need to do permission management or make judgments in programs. Enumerations are relatively simple and can be demonstrated directly in code below:

enum Direction{
    Up,
    Down,
    Left,
    Right
}

console.log(Direction.Up) / / 0
console.log(Direction.Down) / / 1
console.log(Direction.Left) / / 2
console.log(Direction.Right) / / 3
console.log(Direction[0]) //Up
Copy the code

In addition to the basic usage above, we can also assign enumerations:

enum Direction{
    Up = 10,
    Down,
    Left,
    Right
}

console.log(Direction.Up) / / 10
Copy the code

2. Constant enumeration

Let’s define a constant, judged against enum.

enum Direction{
    Up = 'Up',
    Down = 'Down',
    Left = 'Left',
    Right = 'Right'
}

// Define a constant that evaluates directly to enum
const value = 'Up';
if(value === Direction.Up){
    console.log('go Up! ') // go Up!
}
Copy the code

Performance is greatly improved by using constant enumerations, which inline any use of the enumeration rather than turning the enumeration into arbitrary Javascript code.

Can all enums use constant enumerations? The answer, of course, is no.

There are two types of enumeration values, constant value enumeration (constant) and computed value enumeration (computed). Only constant value enumerations can be constant enumerations; computed value enumerations cannot be constant enumerations.

Seven, generics

Let’s move on to the hardest part of TypeScript, generics.

1. Generic types

Generics, generics. When we define a function, interface, or class, we do not specify the type up front, but specify the type and its characteristics as we use it.

In other words, a generic type is a placeholder or variable that can be filled in dynamically as we use it to determine the value of our type.

Let’s use code to demonstrate:

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

const result = echo(true)
console.log(result) // true

Copy the code

We define an unknown generic with <>, and then when we assign a value to it, we can specify the data type of the value.


Now let’s use generics to define an array of type number. The specific code is as follows:

// Define an array of type number
let arr: number[] = [1.2.3]
// Use a generic to define an array of type number
let arrTwo: Array<number> = [1.2.3]
Copy the code

If we now want to swap the position of two elements, we can do so with generics. The specific code is as follows:

function swap<T.U> (tuple: [T, U]) :U.T]{
    return [tuple[1], tuple[0]]}const result2 = swap(['abc'.123])
console.log(result2[0]) / / 123
console.log(result2[1]) //abc
Copy the code

With generics, we have successfully transposed the two elements.

2. Constrain generics

Using the extends keyword in generics lets you pass in values that meet our specific constraints, rather than passing them in randomly for no reason.

For example, if we want the content we define to be an array, we can do that. The specific code is as follows:

function echoWithArr<T> (arg: T[]) :T[]{
    console.log(arg.length)
    return arg
}
const arrs = echoWithArr([1.2.3])
Copy the code

Thus, arRS is defined as an array.


Suppose we now want the length method to be accessible to the content we define, then we need to add a little seasoning. The specific code is as follows:

interface IWithLength{
    length: number
}

function echoWithLength<T extends IWithLength> (arg: T) :T{
    console.log(arg.length)
    return arg
}

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

Extending a specific interface through the extends keyword allows us to define things like STR, obj, and arr2 that can access the Length method.

From the examples above, we can see that generics can be used to flexibly constrain the types of parameters. The parameters need not be a particularly rigid type, but we can use our constraints to achieve the desired purpose.

Use of generics in classes and interfaces

(1) The use of generics in classes

class Queue<T>{
    private data = []
    push(item: T){
        return this.data.push(item)
    }
    pop(): T{
        return this.data.shift()
    }
}
// Make sure this is a queue of type number
const queue = new Queue<number>()
queue.push(1)
console.log(queue.pop().toFixed())
Copy the code

(2) The use of generics in interfaces

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

As you can see from the above code demonstration, generics is like creating a container with a specific type, just like labeling a container.

Type aliases

Type aliases

A type alias, or Type aliase. Type aliases can be seen as a shortcut to create a simpler version of a type that is cumbersome to write. Such as:

(x: number, y: number) => number
let sum: (x: number, y: number) = > number
const result = sum(1.2)

// Alias the type with type
type PlusType = (x: number, y: number) = > number
let sum2: PlusType
const result2 = sum2(2.3)

// A type can be either a string or a number
type StrOrNumber = string | number
let result3: StrOrNumber = '123'
result3 = 123
Copy the code

String literals

String literals, which provide a series of handy constants. Such as:

const str: 'name' = 'name'
const number: 1 = 1
type Direction = 'Up' | 'Down' | 'Left' | 'Right'
let toWhere: Direction = 'Left'
Copy the code

3. Cross types

Cross types, a way to extend an object using type. Such as:

interface IName{
    name: string
}
type IPerson = IName & {age: number}
let person: IPerson = {name: 'monday'.age: 18}
Copy the code

Declaration Documents

When we write TS, we will inevitably have to introduce third party libraries. That’s when you need ts to do special processing. There are two main methods:

1. Import.d.ts files

If we want to import the JQuery library to use, we can add a new jquery.d. ts file externally. The code inside the file is as follows:

declare var JQuery: (selector: string) = > any;
Copy the code

You can then reference the JQuery libraries in the ts file we define. Such as:

jQuery('#foo')
Copy the code

2. NPM installation

We can also install the NPM package of the corresponding third-party library. If we were to introduce a JQuery library now, we could do this.

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

Built-in types

When we write TS code, we are already using a lot of built-in objects. Objects are objects that exist in the global scope according to the standard (ECMA, DOM, etc.). When we run TSC, these built-in objects will be loaded as additional gifts to the program. Let’s take a look at several common built-in objects.

Global object:

// global object Global object
const a: Array<number> = [1.2.3]
const date = new Date()
date.getTime()
const reg = /abc/
reg.test('abc')
Copy the code

Built-in objects:

// build-in object Specifies a built-in object
Math.pow(2.2)
Copy the code

DOM and BOM objects:

/ / DOM and BOM
let body = document.body
let allLis = document.querySelectorAll('li')
allLis.keys()

document.addEventListener('click'.e= > {
    e.preventDefault()
})
Copy the code

Functional types:

// Utility Types
interface IPerson{
    name: string
    age: number
}

let monday: IPerson = {name: 'monday'.age: 20}

// Optional attribute
type IPartial = Partial<IPerson>
let monday2: Ipartial = {name: 'monday'}

// Remove an attribute
type Omit = Omit<IPerson, 'name'>
let monday3: Omit = {age: 20}
Copy the code

11. Conclusion

So much for the introduction to TS! I hope you can have a simple understanding of TS!

If there is any misunderstanding or mistake in this article, please leave a message in the comment area or add my wechat to communicate in the background of the public account

  • Pay attention to the public number Monday laboratory, the first time to pay attention to learning dry goods, more selected columns for you to unlock ~
  • If this article is useful to you, be sure to like it and follow it
  • See you next time! 🥂 🥂 🥂