TypeScript + Vue3 Quick Start [Top]

TypeScript + Vue3 Quick Start [Top]

Hello, everyone, I am also learning TS recently. Before I learn Vue3, it is still necessary to understand some TypeScript related knowledge, let us learn together!

1. Get to know TypeScript

Introduction to TypeScript

TypeScript is an open source, cross-platform programming language developed by Microsoft. It is a superset of JavaScript and will eventually be compiled into JavaScript code.

In October 2012, Microsoft released the first public version of TypeScript. On June 19, 2013, after a preview version, Microsoft officially released the official version of TypeScript.

The author of TypeScript is Anders Heelsberg, the chief architect of C#. It is an open source and cross-platform programming language.

TypeScript extends the syntax of JavaScript, so any existing JavaScript program can run in the TypeScript environment.

TypeScript is designed for the development of large-scale applications and can be compiled into JavaScript.

TypeScript is a superset of JavaScript. It mainly provides a type system and support for ES6+**. It is developed by Microsoft and the code is open source on GitHub

TypeScript is a superset of JavaScript. It mainly provides type system and support for ES6+. It is developed by Microsoft and the code is open source on GitHub (opens new window)

Features of TypeScript

TypeScript has three main features:

Started from JavaScript, attributed to JavaScript TypeScript can compile pure and concise JavaScript code, and it can run on any browser, Node.js environment, and any JavaScript engine that supports ECMAScript 3 (or higher).

Powerful Type System The type system allows JavaScript developers to use efficient development tools and common operations such as static checking and code refactoring when developing JavaScript applications.

Advanced JavaScript TypeScript provides the latest and evolving JavaScript features, including those from ECMAScript in 2015 and future proposals, such as asynchronous functions and Decorators, to help build robust components.

summary

TypeScript is becoming more and more popular in the community. It is very suitable for some large-scale projects and also very suitable for some basic libraries, which greatly helps us improve the development efficiency and experience.

2. Install TypeScript

Run the following command from the command line to install TypeScript globally:

npm install -g typescript copy the code

After the installation is complete, run the following command on the console to check whether the installation is successful (3.x):

tsc -VCopy code

3. The first TypeScript program

Write TS program

src/helloworld.ts

function greeter (person) { return'Hello, '+ person } let user ='Yee' console.log(greeter(user)) Copy code

Manually compile the code

We used the .ts extension, but this code is just JavaScript.

On the command line, run the TypeScript compiler:

tsc helloworld.tsCopy code

The output result is a helloworld.js file, which contains the same JavsScript code as in the input file.

On the command line, run this code through Node.js:

node helloworld.jsCopy code

Console output:

Hello, YeeCopy code

vscode automatic compilation

1). Generate configuration file tsconfig.json

tsc --init copy the code

2). Modify tsconfig.json configuration

"outDir": "./js", "strict": false, Copy code

3). Start the monitoring task:

Terminal -> Run Tasks -> Monitoring tsconfig.json copy the code

Type annotation

Next, let's take a look at the advanced features brought by the TypeScript tool. Add to the parameter of the person function: string type annotation, as follows:

function greeter (person: string) { return'Hello, '+ person } let user ='Yee' console.log(greeter(user)) Copy code

Type annotations in TypeScript are a lightweight way to add constraints to functions or variables. In this example, we want the greeter function to receive a string parameter. Then try to change the call of greeter to pass in an array:

function greeter (person: string) { return'Hello, '+ person } let user = [0, 1, 2] console.log(greeter(user)) Copy code

Recompile and you will see an error:

error TS2345: Argument of type'number[]' is not assignable to parameter of type'string'
. Similarly, try to delete all the parameters of the greeter call. TypeScript will tell you that this function was called with an unexpected number of parameters. In both cases, TypeScript provides static code analysis, which can analyze the code structure and type annotations provided.

It should be noted that despite the error, the greeter.js file was created. Even if there are errors in your code, you can still use TypeScript. But in this case, TypeScript will warn you that the code may not execute as expected.

interface

Let us continue to extend this sample application. Here we use an interface to describe an object with firstName and lastName fields. In TypeScript, only the internal structures of the two types are compatible, then the two types are compatible. This allows us to ensure that the structure required by the interface is included when implementing the interface without having to explicitly use the implements statement.

interface Person { firstName: string lastName: string } function greeter (person: Person) { return'Hello, '+ person.firstName +' '+ person.lastName } let user = { firstName:'Yee', lastName:'Huang' } console.log(greeter(user)) Copy code

class

Finally, let's rewrite this example using classes. TypeScript supports new features of JavaScript, such as support for class-based object-oriented programming.

Let's create a User class with a constructor and some public fields. Because the fields of the class contain the fields required by the interface, they are very compatible.

It should also be noted that I will indicate all member variables in the class declaration, so that the comparison is clear at a glance.

class User { fullName: string firstName: string lastName: string constructor (firstName: string, lastName: string) { this.firstName = firstName this.lastName = lastName this.fullName = firstName + '' + lastName } } interface Person { firstName: string lastName: string } function greeter (person: Person) { return'Hello, '+ person.firstName +' '+ person.lastName } let user = new User('Yee','Huang') console.log(greeter(user)) Copy code

Re-run tsc greeter.ts, you will see that the classes in TypeScript are just a syntactic sugar, essentially the implementation of JavaScript functions.

summary

At this point, you already have a general impression of TypeScript, so let's learn some common syntax of TypeScript together in the next chapter.

4. Use webpack to package TS

  • Download dependencies (note here that you must install dependencies strictly in accordance with the following versions, high versions will cause problems)

    yarn add -D typescript@4.0.5 yarn add -D webpack@4.41.5 webpack-cli@3.3.10 yarn add -D webpack-dev-server@3.10.2 yarn add -D html-webpack-plugin@4.5.0 clean-webpack-plugin yarn add -D ts-loader yarn add -D cross-env Copy code
  • Entry JS: src/main.ts

    //import'./01_helloworld' document.write('Hello Webpack TS!') Copy code
  • index page: public/index.html

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>webpack & TS</title> </head> <body> </body> </html> Copy code
  • build/webpack.config.js

    const {CleanWebpackPlugin} = require('clean-webpack-plugin') const HtmlWebpackPlugin = require('html-webpack-plugin') const path = require('path') const isProd = process.env.NODE_ENV ==='production'//Is it a production environment function resolve (dir) { return path.resolve(__dirname,'..', dir) } module.exports = { mode: isProd?'production':'development', entry: { app:'./src/main.ts' }, output: { path: resolve('dist'), filename:'[name].[contenthash:8].js' }, module: { rules: [ { test:/\.tsx?$/, use:'ts-loader', include: [resolve('src')] } ] }, plugins: [ new CleanWebpackPlugin({ }), new HtmlWebpackPlugin({ template:'./public/index.html' }) ], resolve: { extensions: ['.ts','.tsx','.js'] }, devtool: isProd?'cheap-module-source-map':'cheap-module-eval-source-map', devServer: { host:'localhost',//host name stats:'errors-only',//package log output output error information port: 8081, open: true }, } Copy code

Configure packaging commands

"dev": "cross-env NODE_ENV=development webpack-dev-server --config build/webpack.config.js", "build": "cross-env NODE_ENV=production webpack --config build/webpack.config.js" Copy code

Run and package

yarn dev yarn build Copy code

TypeScript common syntax

1. Basic Type

TypeScript supports almost the same data types as JavaScript, and also provides practical enumeration types for us to use.

  • Boolean value

The most basic data type is a simple true/false value, called boolean in JavaScript and TypeScript (the same in other languages).

let isDone: boolean = false; isDone = true; //isDone = 2//error Copy code
  • digital

Like JavaScript, all numbers in TypeScript are floating point numbers. The type of these floating-point numbers is number. In addition to supporting decimal and hexadecimal literals, TypeScript also supports the binary and octal literals introduced in ECMAScript 2015.

let a1: number = 10//decimal let a2: number = 0b1010//binary let a3: number = 0o12//octal let a4: number = 0xa//hexadecimal Copy code
  • String

Another basic operation of a JavaScript program is to process text data on a web page or server side. Like in other languages, we use string to represent the text data type. Like JavaScript, you can use double quotation marks (") or single quotation marks (') to represent strings.

let name:string ='tom' name ='jack' //name = 12//error let age:number = 12 const info = `My name is ${name}, I am ${age} years old!` Copy code
  • undefined and null

In TypeScript, undefined and null each have their own types called undefined and null. Their own types are not very useful:

let u: undefined = undefined let n: null = null Copy code

By default, null and undefined are subtypes of all types. That means you can assign null and undefined to variables of type number.

  • Array

TypeScript can manipulate array elements just like JavaScript. There are two ways to define an array. The first type can be followed by an element type with [] to indicate an array composed of elements of this type:

let list1: number [] = [ 1, 2, 3] copy the code

The second way is to use array generics, Array<element type>:

let list2: Array <number> = [1, 2, 3] copy the code
  • Tuple

The tuple type allows to represent an array with a known number and type of elements, and the type of each element need not be the same. For example, you can define a pair of tuples whose values are string and number.

let t1: [string, number] t1 = ['hello', 10]//OK t1 = [10,'hello']//Error Copy code

When accessing an element with a known index, you will get the correct type:

console.log(t1[0].substring(1))//OK console.log(t1[1].substring(1))//Error,'number' does not exist in'substring' method Copy code
  • enumerate

The enum type is a supplement to the JavaScript standard data type. Use enumerated types to give friendly names to a set of values.

enum Color { Red, Green, Blue } //The enumeration value is incremented from 0 by default //Get the corresponding enumeration value according to the specific name let myColor: Color = Color.Green//0 console.log(myColor, Color.Red, Color.Blue) Copy code

By default, the element number starts from 0. You can also manually specify the value of the member. For example, we change the above example to start numbering from 1:

enum Color {Red = 1, Green, Blue} let c: Color = Color.Green Copy code

Or, all use manual assignment:

enum Color {Red = 1, Green = 2, Blue = 4} let c: Color = Color.Green Copy code

One convenience provided by enumeration types is that you can get its name from the value of the enumeration. For example, if we know the value is 2, but we are not sure which name in Color it maps to, we can look up the corresponding name:

enum Color {Red = 1, Green, Blue} let colorName: string = Color[2] console.log(colorName)//'Green' Copy code
  • any

Sometimes, we want to specify a type for variables whose types are not yet known at the programming stage. These values may come from dynamic content, such as user input or third-party code libraries. In this case, we don't want the type checker to check these values but directly let them pass the check at the compilation stage. Then we can use the any type to mark these variables:

let notSure: any = 4 notSure ='maybe a string' notSure = false//can also be a boolean Copy code

The any type is very useful when rewriting existing code. It allows you to optionally include or remove type checking at compile time. And when you only know the type of part of the data, the any type is also useful. For example, you have an array that contains different types of data:

let list: any[] = [1, true,'free'] list[1] = 100 Copy code
  • void

To some extent, the void type is like the opposite of the any type, which means that there is no type. When a function does not return a value, you will usually see that its return value type is void:

/* means that there is no type, generally used to indicate that the return value of the function cannot be a value other than undefined and null*/ function fn(): void { console.log('fn()') //return undefined //return null //return 1//error } Copy code

Declaring a variable of type void is useless, because you can only assign undefined and null to it:

let unusable: void = undefined duplicated code
  • object

object represents a non-primitive type, that is, types other than number, string, and boolean.

Using the object type, you can better represent APIs like Object.create. E.g:

function fn2(obj:object):object { console.log('fn2()', obj) return {} //return undefined //return null } console.log(fn2(new String('abc'))) //console.log(fn2('abc')//error console.log(fn2(String)) Copy code
  • Union type

Union Types (Union Types) means that the value can be one of multiple types

  1. Requirement 1: Define a function to get the string form value of a number or string value

    function toString2(x: number | string): string {return x.toString()}

  2. Requirement 2: Define a function to get the length of a number or string value

    function getLength(x: number | string) { //return x.length//error if (x.length) {//error return x.length } else { return x.toString().length } } Copy code
  • Type assertion

Through type assertion, you can tell the compiler, "Trust me, I know what I'm doing." Type assertion is like type conversion in other languages, but without special data checking and deconstruction. It has no runtime impact, but only works during the compilation phase. TypeScript will assume that you, the programmer, have already performed the necessary checks.

There are two forms of type assertions. One is the "angle bracket" syntax, and the other is the as syntax

/* Type Assertion: can be used to manually specify the type of a value syntax: Method one: <type> value Method 2: Value as type tsx can only be used in this way */ /* Requirements: Define a function to get the length of a string or numeric data*/ function getLength(x: number | string) { if ((<string>x).length) { return (x as string).length } else { return x.toString().length } } console.log(getLength('abcd'), getLength(1234)) Copy code
  • Type inference

Type inference: TS will infer that a type is in the following two situations when there is no clear specified type: 1. Assigned when the variable is defined, it is inferred to the corresponding type. 2. When the variable is defined without a value, it is inferred to be the any type

/* Assigned when the variable is defined, it is inferred to be the corresponding type*/ let b9 = 123//number //b9 ='abc'//error /* There is no assignment when the variable is defined, and it is inferred to be of the any type*/ let b10//any type b10 = 123 b10 ='abc' Copy code

2. Interface

One of the core principles of TypeScript is to type-check the structure of the value. We use Interfaces to define the type of objects. Interface is the abstraction (description) of the state (attribute) and behavior (method) of the object

  • A preliminary exploration of the interface

Requirement: To create an object of a person, certain constraints must be imposed on the attributes of the person

id is number type, must have, read-only name is string type, must have age is number type, must have sex is string type, it can be absent Copy code

Here is a simple example to observe how the interface works:

/* In TypeScript, we use Interfaces to define the type of objects Interface: It is the abstract (description) of the state (attribute) and behavior (method) of the object Interface type object More or less attributes are not allowed Optional attributes:? Read-only attribute: readonly */ /* Requirement: To create an object of a person, certain constraints must be imposed on the attributes of the person id is number type, must have, read-only name is string type, must have age is number type, must have sex is string type, you can have none */ //Define human interface interface IPerson { id: number name: string age: number sex: string } const person1: IPerson = { id: 1, name:'tom', age: 20, sex:'male' } Copy code

The type checker will check whether the internal properties of the object are consistent with the IPerson interface description. If they are inconsistent, it will prompt a type error.

  • Optional attributes

Not all attributes in the interface are required. Some exist only under certain conditions, or do not exist at all.

interface IPerson { id: number name: string age: number sex?: string } Copy code

Interfaces with optional attributes are similar to ordinary interface definitions, except that a? Symbol is added after the definition of optional attribute names.

One of the benefits of optional attributes is that you can predefine the attributes that may exist, and the second benefit is that you can catch errors when referring to non-existent attributes.

const person2: IPerson = { id: 1, name:'tom', age: 20, //sex:'male'//no } Copy code
  • Read-only attribute

Some object properties can only be modified when the object is just created. You can specify read-only attributes with readonly before the attribute name:

interface IPerson { readonly id: number name: string age: number sex?: string } Copy code

Once assigned, it cannot be changed anymore.

const person2: IPerson = { id: 2, name:'tom', age: 20, //sex:'male'//no //xxx: 12//error is not defined in the interface, cannot have } person2.id = 2//error Copy code
  • readonly vs const

The easiest way to determine whether to use readonly or const is to use it as a variable or as an attribute. If used as a variable, use const, if used as an attribute, use readonly.

  • Function type

Interfaces can describe the various appearances of objects in JavaScript. In addition to describing ordinary objects with attributes, interfaces can also describe function types.

In order to use the interface to represent the function type, we need to define a call signature for the interface. It is like a function definition with only a parameter list and return value type. Each parameter in the parameter list needs a name and type.

/* Interface can describe function type (parameter type and return type) */ interface SearchFunc { (source: string, subString: string): boolean } Copy code

After this definition, we can use the interface of this function type like other interfaces. The following example shows how to create a variable of function type and assign a function of the same type to this variable.

const mySearch: SearchFunc = function (source: string, sub: string): boolean { return source.search(sub)> -1 } console.log(mySearch('abcd','bc')) Copy code
  • Class type
  1. Class implements interface

Like the basic function of the interface in C# or Java, TypeScript can also use it to explicitly force a class to conform to a certain contract.

/* Class type: implement interface 1. A class can implement multiple interfaces 2. An interface can inherit multiple interfaces */ interface Alarm { alrt(): any; } interface Light { lightOn(): void; lightOff(): void; } class Car implements Alarm { alrt() { console.log('Car alert'); } } Copy code

2. A class can implement multiple interfaces

class Car2 implements Alarm, Light { alrt() { console.log('Car alert'); } lightOn() { console.log('Car light on'); } lightOff() { console.log('Car light off'); } } Copy code
  1. Interface inherits interface

Like classes, interfaces can also inherit from each other. This allows us to copy members from one interface to another interface, which allows us to split the interface into reusable modules more flexibly.

interface LightableAlarm extends Alarm, Light { } Copy code

3. Class

For traditional JavaScript programs we will use functions and prototype-based inheritance to create reusable components, but for programmers who are familiar with object-oriented methods, using these syntaxes is a bit tricky, because they use class-based inheritance and objects are Constructed by classes. Starting from ECMAScript 2015, which is ES6, JavaScript programmers will be able to use a class-based object-oriented approach. With TypeScript, we allow developers to use these features now, and the compiled JavaScript can run on all major browsers and platforms without waiting for the next JavaScript version.

  • Basic example

Let's look at an example of using classes:

/* Basic definition and use of classes */ class Greeter { //Declare attributes message: string //Construction method constructor (message: string) { this.message = message } //general method greet (): string { return'Hello '+ this.message } } //Create an instance of the class const greeter = new Greeter('world') //call the method of the instance console.log(greeter.greet()) Copy code

If you have used C# or Java, you will be very familiar with this syntax. We declare a Greeter class. This class has 3 members: an attribute called message, a constructor and a greet method.

You will notice that we use this when referencing any class member. It means that we are accessing members of the class.

In the following line, we use new to construct an instance of the Greeter class. It will call the previously defined constructor, create a new object of type Greeter, and execute the constructor to initialize it.

The last line calls its greet method through the greeter object

  • inherit

In TypeScript, we can use common object-oriented patterns. One of the most basic patterns in class-based programming is to allow the use of inheritance to extend existing classes.

Look at the following example:

/* Class inheritance */ class Animal { run (distance: number) { console.log(`Animal run ${distance}m`) } } class Dog extends Animal { cry () { console.log('wang! wang!') } } const dog = new Dog() dog.cry() dog.run(100)//You can call the method inherited from the parent Copy code

This example shows the most basic inheritance: the class inherits properties and methods from the base class. Here, Dog is a derived class, which is derived from the Animal base class through the extends keyword. Derived classes are usually called subclasses, and base classes are usually called superclasses.

Because Dog inherits the functions of Animal, we can create an instance of Dog, which can cry() and run().

Let's look at a more complicated example.

class Animal { name: string constructor (name: string) { this.name = name } run (distance: number=0) { console.log(`${this.name} run ${distance}m`) } } class Snake extends Animal { constructor (name: string) { //Call the super type construction method super(name) } //Override the method of the parent type run (distance: number=5) { console.log('sliding...') super.run(distance) } } class Horse extends Animal { constructor (name: string) { //Call the super type construction method super(name) } //Override the method of the parent type run (distance: number=50) { console.log('dashing...') //Call the general method of the parent type super.run(distance) } xxx () { console.log('xxx()') } } const snake = new Snake('sn') snake.run() const horse = new Horse('ho') horse.run() //The parent type reference points to an instance of the child type ==> polymorphism const tom: Animal = new Horse('ho22') tom.run() /* If the subtype has no extension methods, you can make the subtype reference point to an instance of the supertype*/ const tom3: Snake = new Animal('tom3') tom3.run() /* If the subtype has extension methods, you cannot let the subtype reference point to an instance of the supertype*/ //const tom2: Horse = new Animal('tom2') //tom2.run() Copy code

This example shows some features not mentioned above. This time, we used the extends keyword to create two subclasses of Animal: Horse and Snake.

The difference from the previous example is that the derived class contains a constructor, which must call super(), which executes the constructor of the base class. Moreover, before accessing the attribute of this in the constructor, we must call super(). This is an important rule enforced by TypeScript.

This example demonstrates how to override the method of the parent class in the subclass. Both the Snake class and the Horse class have created a run method, which overrides the run method inherited from Animal, so that the run method has different functions according to different classes. Note that even if tom is declared as an Animal type, because its value is Horse, when tom.run(34) is called, it will call the overridden method in Horse.

sliding... sn run 5m dashing... ho run 50m Copy code
  • Public, private and protected modifiers
  1. The default is public

In the above example, we can freely access the members defined in the program. If you have a better understanding of classes in other languages, you will notice that we did not use public to make decorations in the previous code; for example, C# requires you to explicitly use public to specify that members are visible. In TypeScript, all members are public by default.

You can also explicitly mark a member as public. We can rewrite the above Animal class in the following way:

2. Understand private

When a member is marked as private, it cannot be accessed outside the class in which it is declared.

3. Understand protected

The protected modifier behaves similarly to the private modifier, but with one difference, protected members can still be accessed in derived classes. E.g:

/* Access modifier: used to describe the accessibility of properties/methods inside the class public: default value, public can also be accessed outside private: can only be accessed inside the class protected: inside the class and subclasses can be accessed */ class Animal { public name: string public constructor (name: string) { this.name = name } public run (distance: number=0) { console.log(`${this.name} run ${distance}m`) } } class Person extends Animal { private age: number = 18 protected sex: string ='Male' run (distance: number=5) { console.log('Person jumping...') super.run(distance) } } class Student extends Person { run (distance: number=6) { console.log('Student jumping...') console.log(this.sex)//The child class can see the protected members in the parent class //console.log(this.age)//subclasses cannot see private members in the parent class super.run(distance) } } console.log(new Person('abc').name)//publicly visible //console.log(new Person('abc').sex)//protected invisible //console.log(new Person('abc').age)//private invisible Copy code
  • readonly modifier

You can use the readonly keyword to set the attribute to be read-only. Read-only properties must be initialized at the time of declaration or in the constructor.

class Person { readonly name: string ='abc' constructor(name: string) { this.name = name } } let john = new Person('John') //john.name ='peter'//error Copy code
  • Parameter attributes

In the above example, we must define a read-only member name and a constructor whose parameter is name in the Person class, and immediately assign the value of name to this.name. This situation is often encountered. Parameter attributes can conveniently allow us to define and initialize a member in one place. The following example is a modified version of the previous Person class, using parameter attributes:

class Person2 { constructor(readonly name: string) { } } const p = new Person2('jack') console.log(p.name) Copy code

Pay attention to how we discard the parameter name, and only use the readonly name: string parameter in the constructor to create and initialize the name member. We merge declaration and assignment into one place.

Parameter attributes are declared by adding an access qualifier in front of the constructor parameters. Using private to qualify a parameter attribute will declare and initialize a private member; the same is true for public and protected.

  • Accessor

TypeScript supports intercepting access to object members through getters/setters. It can help you effectively control access to object members.

Let's see how to rewrite a simple class to use get and set. 1. we start with an example that does not use an accessor.

class Person { firstName: string ='A' lastName: string ='B' get fullName () { return this.firstName +'-' + this.lastName } set fullName (value) { const names = value.split('-') this.firstName = names[0] this.lastName = names[1] } } const p = new Person() console.log(p.fullName) p.firstName ='C' p.lastName ='D' console.log(p.fullName) p.fullName ='EF' console.log(p.firstName, p.lastName) Copy code
  • Static properties

So far, we have only discussed the instance members of the class, those properties that are initialized only when the class is instantiated. We can also create static members of the class, these properties exist on the class itself rather than on the instance of the class. In this example, we use static to define origin because it is an attribute that all grids will use. When each instance wants to access this attribute, it must add the class name in front of the origin. Just like using this.xxx to access properties on instance properties, here we use Grid.xxx to access static properties.

/* Static properties, which are properties of class objects Non-static properties, which are properties of instance objects of the class */ class Person { name1: string ='A' static name2: string ='B' } console.log(Person.name2) console.log(new Person().name1) Copy code
  • Abstract class

Abstract classes are used as base classes for other derived classes. They cannot be instantiated. Unlike interfaces, abstract classes can contain the implementation details of members. The abstract keyword is used to define abstract classes and define abstract methods inside abstract classes.

/* Abstract class Cannot create instance objects, only implementation classes can create instances Can contain unimplemented abstract methods */ abstract class Animal { abstract cry () run () { console.log('run()') } } class Dog extends Animal { cry () { console.log(' Dog cry()') } } const dog = new Dog() dog.cry() dog.run() Copy code

4. Functions

Functions are the foundation of JavaScript applications, which help you implement abstraction layers, simulation classes, information hiding, and modules. In TypeScript, although classes, namespaces, and modules are already supported, functions are still the main place to define behavior. TypeScript adds extra features to JavaScript functions so that we can use them more easily.

  • Basic example

Like JavaScript, TypeScript functions can create named functions and anonymous functions. You can choose the method that suits the application at will, whether it is to define a series of API functions or functions that are used only once.

You can quickly recall the functions in these two types of JavaScript through the following examples:

//named function function add(x, y) { return x + y } //Anonymous function let myAdd = function(x, y) { return x + y; } Copy code
  • Function type
  1. Define the type for the function

Let's add a type to the above function:

function add(x: number, y: number): number { return x + y } let myAdd = function(x: number, y: number): number { return x + y } Copy code

We can add a type to each parameter and then add a return value type to the function itself. TypeScript can automatically infer the return value type based on the return statement.

  1. Write the complete function type

Now that we have specified the type for the function, let's write the complete type of the function.

let myAdd2: (x: number, y: number) => number = function(x: number, y: number): number { return x + y } Copy code
  • Optional and default parameters

Every function parameter in TypeScript is required. This does not mean that you cannot pass null or undefined as parameters, but that the compiler checks whether the user has passed a value for each parameter. The compiler also assumes that only these parameters will be passed into the function. In short, the number of parameters passed to a function must match the number of parameters expected by the function.

In JavaScript, each parameter is optional and can be passed or not. When no parameter is passed, its value is undefined. In TypeScript, we can use? Beside the parameter name to realize the function of optional parameters. For example, we want lastName to be optional:

In TypeScript, we can also provide a default value for the parameter when the user does not pass the parameter or the passed value is undefined. They are called parameters with default initialization values. Let us modify the above example and set the default value of firstName to "A".

function buildName(firstName: string='A', lastName?: string): string { if (lastName) { return firstName +'-' + lastName } else { return firstName } } console.log(buildName('C','D')) console.log(buildName('C')) console.log(buildName()) Copy code

Remaining parameters

Necessary parameters, default parameters and optional parameters have one thing in common: they represent a certain parameter. Sometimes, you want to manipulate multiple parameters at the same time, or you don't know how many parameters will be passed in. In JavaScript, you can use arguments to access all incoming parameters.

In TypeScript, you can collect all parameters into one variable: The remaining parameters will be treated as an unlimited number of optional parameters. There can be none, or any number. The compiler creates an array of parameters. The name is the name you give after the ellipsis (...). You can use this array in the function body.

function info(x: string, ...args: string[]) { console.log(x, args) } info('abc','c','b','a') Copy code
  • Function overloading

Function overloading: Multiple functions with the same function name but different formal parameters can be mismatched in JS due to the characteristics of weak types and the formal parameters involved. There is no such thing as function overloading. But in TS, it is different from other functions. Object-oriented languages (such as Java) have this syntax

/* Function overloading: multiple functions with the same function name but different formal parameters Requirements: We have an add function, which can receive two string type parameters for splicing, or two number type parameters for addition */ //overloaded function declaration function add (x: string, y: string): string function add (x: number, y: number): number //Define function implementation function add(x: string | number, y: string | number): string | number { //In the implementation, we must pay attention to strictly judging whether the types of two parameters are equal, instead of simply writing x + y if (typeof x ==='string' && typeof y ==='string') { return x + y } else if (typeof x ==='number' && typeof y ==='number') { return x + y } } console.log(add(1, 2)) console.log(add('a','b')) //console.log(add(1,'a'))//error Copy code

5. Generic

Refers to a characteristic that does not specify a specific type in advance when defining a function, interface, or class, but specifies a specific type when using it.

  • Introduce

Create a function below to realize the function: According to the specified number count and data value, create an array containing count values without generics, this function may be as follows:

function createArray(value: any, count: number): any[] { const arr: any[] = [] for (let index = 0; index <count; index++) { arr.push(value) } return arr } const arr1 = createArray(11, 3) const arr2 = createArray('aa', 3) console.log(arr1[0].toFixed(), arr2[0].split('')) Copy code
  • Use function generics

    function createArray2 <T> (value: T, count: number) { const arr: Array<T> = [] for (let index = 0; index <count; index++) { arr.push(value) } return arr } const arr3 = createArray2<number>(11, 3) console.log(arr3[0].toFixed()) //console.log(arr3[0].split(''))//error const arr4 = createArray2<string>('aa', 3) console.log(arr4[0].split('')) //console.log(arr4[0].toFixed())//error Copy code
  • Functions with multiple generic parameters

A function can define multiple generic parameters

function swap <K, V> (a: K, b: V): [K, V] { return [a, b] } const result = swap<string, number>('abc', 123) console.log(result[0].length, result[1].toFixed()) Copy code
  1. Generic interface

When defining the interface, define the generic type for the attributes or methods in the interface. When using the interface, specify the specific generic type.

interface IbaseCRUD <T> { data: T[] add: (t: T) => void getById: (id: number) => T } class User { id?: number;//id primary key self-increment name: string;//Name age: number;//age constructor (name, age) { this.name = name this.age = age } } class UserCRUD implements IbaseCRUD <User> { data: User[] = [] add(user: User): void { user = {...user, id: Date.now()} this.data.push(user) console.log('Save user', user.id) } getById(id: number): User { return this.data.find(item => item.id===id) } } const userCRUD = new UserCRUD() userCRUD.add(new User('tom', 12)) userCRUD.add(new User('tom2', 13)) console.log(userCRUD.data) Copy code
  1. Generic class

When defining a class, define a generic type for the attributes or methods in the class. When creating an instance of the class, specify a specific generic type.

class GenericNumber<T> { zeroValue: T add: (x: T, y: T) => T } let myGenericNumber = new GenericNumber<number>() myGenericNumber.zeroValue = 0 myGenericNumber.add = function(x, y) { return x + y } let myGenericString = new GenericNumber<string>() myGenericString.zeroValue ='abc' myGenericString.add = function(x, y) { return x + y } console.log(myGenericString.add(myGenericString.zeroValue,'test')) console.log(myGenericNumber.add(myGenericNumber.zeroValue, 12)) Copy code
  1. Generic constraints

If we directly take the length attribute to a generic parameter, an error will be reported, because the generic doesn t even know that it has this attribute

//No generic constraints function fn <T>(x: T): void { //console.log(x.length)//error } Copy code

We can use generic constraints to achieve

interface Lengthwise { length: number; } //Specify generic constraints function fn2 <T extends Lengthwise>(x: T): void { console.log(x.length) } Copy code

We need to pass in a value that meets the constraint type, which must include the length attribute:

fn2('abc') //fn2(123)//error number has no length attribute Copy code

6. Other

  • Declaration file

When using a third-party library, we need to reference its declaration file to get the corresponding code completion, interface prompts and other functions

What is a declaration statement

If we want to use the third-party library jQuery, a common way is to pass in html

But in ts, the compiler does not know what $ or jQuery is

/* When using a third-party library, we need to reference its declaration file to get the corresponding code completion, interface prompts and other functions. Declaration statement: If you need ts to check the new syntax, you need to load the corresponding type description code declare var jQuery: (selector: string) => any; Declaration file: Put the declaration statement in a separate file (jQuery.d.ts), ts will be automatically parsed to all declaration files in the project Download the declaration file: npm install @types/jquery --save-dev */ jQuery('#foo'); //ERROR: Cannot find name'jQuery'. Copy code

At this time, we need to use declare var to define its type

declare var jQuery: (selector: string) => any; jQuery('#foo'); Copy code

declare var does not really define a variable, but only defines the type of the global variable jQuery, which will only be used for compile-time checks and will be deleted in the compilation result. The result of its compilation is:

jQuery('#foo'); Copy code

Generally, the declaration file will be written as a separate xxx.d.ts file

Create 01_jQuery.d.ts, define the declaration statement in it, and the TS compiler will scan and load all the TS declaration files in the project

declare var jQuery: (selector: string ) => any; duplicated code

Many third-party libraries have defined corresponding declaration file libraries. The library file name is generally @types/xxx, which can be searched at www.npmjs.com/package/pac...

Some third libraries will automatically download the corresponding declaration file library when downloading (for example: webpack), and some may need to be downloaded separately (for example, jQuery/react)

  • Built-in objects

There are many built-in objects in JavaScript, which can be directly used as defined types in TypeScript.

Built-in objects refer to objects that exist in the global scope (Global) according to the standard. The standard here refers to the standards of ECMAScript and other environments (such as DOM).

Built-in objects of ECMAScript

Boolean Number String Date RegExp Error

/* 1. Built-in objects of ECMAScript*/ let b: Boolean = new Boolean(1) let n: Number = new Number(true) let s: String = new String('abc') let d: Date = new Date() let r: RegExp =/^1/ let e: Error = new Error('error message') b = true //let bb: boolean = new Boolean(2)//error Copy code

Built-in objects of BOM and DOM

Window Document HTMLElement DocumentFragment Event NodeList

const div: HTMLElement = document.getElementById('test') const divs: NodeList = document.querySelectorAll('div') document.addEventListener('click', (event: MouseEvent) => { console.dir(event.target) }) const fragment: DocumentFragment = document.createDocumentFragment() Copy code

Okay, let s share it today, the next one is related to Vue3! Interested friends support and support!