The preface

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

3. Run the TS file

NPM I [email protected] -g ts-node demo.tsCopy the code

Create the TS project

npm init -y
tsc --init
npm i ts-node -D
npm i typescript -D
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

This method is called typeof syntax for type protection.

3) Moving on, let’s look at another way to do type protection, the in syntax. The specific code is as follows:

interface Bird {
    fly: Boolean;
    sing: () = > {};
}

interface Dog {
    fly: boolean;
    bark: () = > {};
}

function trainAnimal(animal: Bird | Dog) {
    if('sing' in animal) {
        animal.sing();
    }else{ animal.bark(); }}Copy the code

In ‘sing’ in animal, we can say animal is a Bird, else. If it’s Bird, then else, it’s going to look for Dog, so it’s going to find the Bark method.

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.

4. Abstract classes

(1) What is abstract class

The so-called abstract class is to pull out some common things, that is, some universal things do some encapsulation.

(2) Take an example

Let’s take an example of how an abstract class is used. The specific code is as follows:

/ / abstract classes
abstract class Geom {
  width: number;
  getType() {
    return 'demo';
  }
  abstract getArea(): number;
}

class Circle extends Geom{
  getArea() {
    return 123; }}class Squre {}
class Triangle{}
Copy the code

(3) Abstract classes and interfaces

As some of you may have noticed, abstract classes seem a bit similar to the interfaces we learned above. So, in fact, an abstract class abstracts out some common methods that are related to a class. Interfaces, on the other hand, are abstractions of objects and properties. That’s the difference between them, but their essence is to encapsulate something universal.

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.

4. Use of keyof syntax in generics

interface Person {
    name: string;
    age: number;
    gender: string;
}

// type T = 'name';
// key: 'name';
// Person['name'];

// type T = 'age';
// key: 'age';
// Person['age'];

// type T = 'gender';
// key: 'gender';
// Person['gender'];

class Teacher {
    constructor(private info: Person) {}
    // keyof keyword
    getInfo<T extends keyof Person>(key: T): Person[T] {
        return this.info[key]; }}const teacher = new Teacher({
    name: 'Monday'.age: 18.gender: 'female'
});

const test = teacher.getInfo('age');
console.log(test);
Copy the code

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

Namespaces

1. What is namespace

If I now have a namespace, the contents of the namespace will not be exposed. The following code looks like this:

namespace Home {
    class Header {
        constructor() {
            const elem = document.createElement('div');
            elem.innerText = 'This is Header';
            document.body.appendChild(elem); }}class Content {
        constructor() {
            const elem = document.createElement('div');
            elem.innerText = 'This is Content';
            document.body.appendChild(elem); }}class Footer {
        constructor() {
            const elem = document.createElement('div');
            elem.innerText = 'This is Footer';
            document.body.appendChild(elem); }}class Page {
        constructor() {
            new Header();
            new Content();
            newFooter(); }}}Copy the code

In the code above, there is a namespace named Home with four classes in total. So at this point, if we want to use one of these classes externally, there’s no way.

What if we want to expose a class in a namespace?

Normally, we would prefix the class with the export keyword. Something like this:

namespace Home {
    // add the export keyword
    export class Header {
        constructor() {
            const elem = document.createElement('div');
            elem.innerText = 'This is Header';
            document.body.appendChild(elem); }}class Content {
        constructor() {
            const elem = document.createElement('div');
            elem.innerText = 'This is Content';
            document.body.appendChild(elem); }}class Footer {
        constructor() {
            const elem = document.createElement('div');
            elem.innerText = 'This is Footer';
            document.body.appendChild(elem); }}class Page {
        constructor() {
            new Header();
            new Content();
            newFooter(); }}}Copy the code

As you can see, by adding the export keyword, you can expose the class externally. Without the keyword export, it is still inaccessible to the outside world.

Now let’s see how it works. The specific code is as follows:

<! DOCTYPE html><html lang="en">

<head>
  <meta charset="UTF-8" />
  <title>Document</title>
  <script src="./dist/page.js"></script>
</head>

<body>
  <script>
    new Home.Header();
  </script>
</body>

</html>
Copy the code

As you can see, new home.header (); We can access the Header class exposed in the namespace Home. However, the other variables without the keyword export cannot be accessed normally. It makes the original four global variables become only Home, which is the benefit of namespace.

2. Benefits of Namespace

Now, let’s take a look at the benefits of namespaces. One of the benefits of namespace is that it allows us to generate as few global variables as possible in a modularity-like development approach. In other words, encapsulate a group of related content together to provide a unified exposed interface to the outside world.

3. Rely on namespace declarations

Suppose we wanted to introduce another namespace into one namespace, how would we use it? The following code looks like this:

The // Home namespace depends on declarations from other namespaces
///<reference path='./components.ts' /> 

namespace Home {
  export class Page {
    user: Components.User = {
      name: 'monday'
    }
    constructor() {
      new Components.Header();
      new Components.Content();
      newComponents.Footer(); }}}Copy the code

///
We can introduce the components namespace for our use.

X. 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:

// First type: define global variables
declare var JQuery: (selector: string) = > any;

// Second type: define global function β†’ transfer function
declare function $(readFunc: () => void) :void;

// Third type: define global function β†’ pass string
interface JQueryInstance {
    html: (html: string) = > {};
}
declare function $(selector: string) :JQueryInstance;
Copy the code

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

$(function() {$('body').html('<div>123</div>');
});
Copy the code

2. Use interface syntax to implement function overloading

The second and third types above implement function overloading using both passing functions and passing strings. So let’s use interface syntax to change the way we overload functions. The.d.ts file code is as follows:

interface JQueryInstance {
    html: (html: string) = > JQueryInstance;
}

// Use interface syntax to implement function overloading
interface JQuery {
    (readFunc: () = > void) :void;
    (selector: strring): JQueryInstance;
}
declare var $: JQuery;
Copy the code

As you can see, we’ve incorporated readFunc and selector into the JQuery interface as an interface, and we’re just going to expose JQuery.

3. Declare objects

Above we have a function overload when $is just a function. What if $is used as both a function and an object? Suppose we now have this code:

$(function() {$('body').html('<div>123</div>');
    new $.fn.init();
})
Copy the code

Now, if we want to access fn and init in $, we need to use $not only as a function, but also as an object. We can do this in the.d.ts file. The specific code is as follows:

interface JQueryInstance {
    html: (html: string) = > JQueryInstance;
} 

// Function overload
declare function $(readyFunc: () => void) :void;
declare function $(selector: string) :JQueryInstance;

// How to type objects, class, and namespace nesting
declare namespace $ { 
    namespace fn {
        class init {}}}Copy the code

As you can see, we’ve defined the namespace, we’ve continued to nest the namespace in the namespace, and we’ve used the class class for the type definition. Finally, we can successfully access $.fn.init()!

4. Modular introduction of NPM

We can also install the corresponding third party library NPM package, which is the type definition file. If we were to introduce a JQuery library now, we could do this.

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

Next, we will modify the.d.ts file with the following code:

// ES6 is modular
declare module 'jquery' {
    interface JQueryInstance {
        html: (html: string) = > JQueryInstance;
    }
    // Mixed type
    function $(readyFunc: () => void) :void;
    function $(selector: string) :JQueryInstance;
    namespace $ {
        namespace fn {
            class init {}}}export = $;
}
Copy the code

Finally, we come to the TS file where we want to introduce $. The specific code is as follows:

import $ from 'jquery';

$(function() {$('body').html('<div>123</123>');
    new $.fn.init();
});
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

Configuration files in TypeScript

When initializing a TS project, we usually run TSC –init and then generate a tsconfig.json file. Under this file, there is a lot of configuration. Let’s take a look at some of the more noteworthy configuration items.

{
    "include": ["./demo.ts"].// Only compile./demo.ts files
    "exclude": ["./demo.ts"].// Do not compile./demo.ts files
    "files": ["./demo.ts"].// Only compile./demo.ts files
    "removeComments": true.// indicates that comments in ts files are removed during packaging
    "noImplicityAny": true.// When set to true, all parameters should be typed, otherwise an error will be reported; When set to false, explicit any is not required
    "strictNullChecks": true.// When set to true, null type checks are enforced. When set to false, null type checks are not enforced
    "rootDir": "./src".// Specify the address of the input file
    "outFile": "./build/page.js".// Finally pack all files into a page.js file in the build directory
    "outDir": "./build".// Specify the address of the output file
    "incremental": true.// Incremental compilation, that is, the previous compilation should not be compiled now
    "allowJs": true.// Allows all files under the specified folder to be compiled
    "checkJs": true.// Check the syntax of compiled JS files
    "sourceMap": true.// The compiled result is regenerated into a.map file
    "noUnusedLocals": true.// Indicate unnecessary code that has no real effect
    "noUnuesdParameters": true.If the parameters in the function are not used, an error message will be displayed
    "baseUrl": ". /".What is the root path in TypeScript
}
Copy the code

Modular organization of code in TS

Above we looked at the use of namespaces and it seemed a bit troublesome. In fact, in TS, we can modularize code, usually through import statements. How do you deal with that?

1. Project structure

2, modular split

, a first step to define the SRC | components. The ts of the code. The specific code is as follows:

export class Header {
    constructor() {
        const elem = document.createElement('div');
        elem.innerText = 'This is Header';
        document.body.appendChild(elem); }}export class Content {
    constructor() {
        const elem = document.createElement('div');
        elem.innerText = 'This is Content';
        document.body.appendChild(elem); }}export class Footer {
    constructor() {
        const elem = document.createElement('div');
        elem.innerText = 'This is Footer';
        document.body.appendChild(elem); }}Copy the code

The second step is to make the call in a modular fashion. In the SRC | page. The ts file, the specific code is as follows:

import { Header, Content, Footer } from './components';

export class Page {
  constructor() {
    new Header();
    new Content();
    newFooter(); }}Copy the code

As you can see, we used the import statement to make modular calls to the class.

The third step is to reference the project in index.html and finally run it. The specific code is as follows:

<! DOCTYPEhtml>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <title>Document</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.js"></script>
  <script src="./build/page.js"></script>
</head>

<body>
  <script>
    require(['page'].function (page) {
      new page.Page();
    });
  </script>
</body>

</html>
Copy the code

As you can see, if you don’t use webpack or other packaging tools, then you need to use CDN to introduce a require library so that you can use the require syntax later.

Finally, let’s take a look at what the browser looks like. The diagram below:

As you can see, the end result is not exactly what we want. In the previous section, we briefly looked at how modules can be split and combined in TypeScript using import statements.

Fourthly, concluding remarks

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

If this article is useful to you, be sure to leave a footprint

One More Thing

Column through train

Column here πŸ‘‰juejin.cn/column/6979…

(: one day

Note: This article is a complement to the previous one, adding some advanced grammar.

That’s all for this article, and we’ll see you next time! πŸ₯‚ πŸ₯‚ πŸ₯‚