Introduce TypeScript
The type of programming language
-
Dynamically typed language
Is a language for datatype checking at run time. In dynamically typed languages such as JavaScript and Python, there is no need to specify a data type for a variable. The first time a value is assigned to a variable, the data type is recorded internally. Errors can only be found at run time, so they may cause some problems. Common static type code checkers are EsLint. Prompt problems according to rules during coding.
-
Statically typed language
Is a language for datatype checking at compile time. When writing programs, you need to declare the data type of variables, such as C, Java.
What is TypeScript?
-
TypeScript transforms type-less dynamic languages into type-focused static languages, which are extensible JavaScript, a superset of JavaScript. In addition to native JavaScript, it also provides a type system.
-
Provides ES6 syntax support.
-
Compatible with various browsers and systems, open source.
The TypeScript’s official website
Why use TypeScript?
-
The program is easier to understand
When you want to know the parameter types of a function method, the code is all comments.
-
More efficient
Different code blocks and definitions for jump, automatic code completion, rich interface prompts.
-
Fewer mistakes
Most errors are found at compile time.
-
Very inclusive
Fully JavaScript compatible, third-party libraries can write type files separately, and most projects support TypeScript.
Install the TypeScript
Install the TypeScript:
npm install -g typescript
Copy the code
View version:
tsc -v
Copy the code
TSC stands for TypeScript Compiler.
Create a TS file:
// hello.ts
// Specify that the name argument is of type string
const hello = (name: string) = > {
return `hello ${name}`;
}
hello('ts');
Copy the code
Compile to js file:
tsc hello.ts
Copy the code
A new js file is generated:
// hello.js
var hello = function (name) {
return "hello ".concat(name);
};
hello('ts');
Copy the code
If there is a problem in the ts file, an error will be reported:
// hello.ts
const hello = (name: string) = > {
return `hello ${name}`;
}
// 123 is not a string
hello(123);
Copy the code
> tsc hello.ts
hello.ts:5:7 - error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.
5 hello(123);
~~~
Found 1 error.
Copy the code
Js files will still be generated:
// hello.js
var hello = function (name) {
return "hello ".concat(name);
};
hello(123);
Copy the code
As you can see, TSC compilation generates results even if an error is reported.
Primitive type and any type
Primitive and any declarations:
let bool: boolean = true;
let num: number = 10;
let str: string = 'ts';
let tempStr: string = `Hello, ${str}`;
let u: undefined = undefined;
let n: null = null;
// undefined and null are subtypes of all types and can be assigned to variables of other types
num = undefined;
let big: bigint = 1n;
let sym: symbol = Symbol(a);// The any type is the top-level type of the type system. Any type can be classified as any
let anyType: any = 123;
anyType = 'string';
anyType = true;
// You can access any properties and methods of any objects
anyType.name;
anyType.add();
Copy the code
Undefined vs. null
-
Similarity: undefined and null are both turned to false in if statements.
-
Original idea: Distinguish null values of primitive and synthesized types. Define a null value of the primitive type as undefined and NaN when converted to a number; A null value of the synthesized type is defined as null, which is 0 when converted to a number. In the end, it’s impossible to tell.
-
Current usage: null means “no object”, there should be no value; Undefined means “missing value”. There should be a value, but it is not defined yet.
Arrays and tuples
// Arrays aggregate data of the same type
let arr: number[] = [1.2];
arr.push(3);
// Class arraylike object cannot use array methods
function foo() {
console.log(arguments);
}
// triple sets the data type of each item. Tuples are arrays
let user: [string.number] = ['Joe'.20];
// The value using the array push can only be one of the types defined by the tuple
user.push(30);
Copy the code
Interface Interface
An interface is a description of the shape of an Object. Using an interface can help define an Object type.
Interface is a duck type. It is more concerned with how the object is used than with the object type itself.
Interface is not a concept in JS and will not be converted to JS after compilation. It can only be used for static type checking.
interface Person {
name: string;
// Optional attributeage? :number;
// A read-only property that can only be assigned at creation time
// readonly for attributes, const for variables
readonly id: number;
}
let Joe: Person = {
name: 'Joe'.age: 20.id: 1
}
// Joe.id = 2; "Id" cannot be assigned because it is a read-only property.
Copy the code
An Interface is like a specification and a contract, with a warning if it is different.
function
The function is a first-class citizen. Functions, like other types of objects, can be taken as arguments, stored in arrays, assigned to variables, and so on.
A function consists of two parts: input and output.
// Specify the input and output of the function
// Function declaration
function add(x: number, y: number./* This parameter is optionalz? :number) :number {
if (typeof z === 'number') {
return x + y + z;
} else {
returnx + y; }}let result: number = add(1.2); / / 3
// Function expression
const add1 = (x: number.y: number) :number= > {
return x + y;
}
// interface describes the function type
interface ISum {
// Parameter type: return value type
(x: number.y: number) :number
}
const add2: ISum = add1;
Copy the code
Type inference
Type inference automatically defines the type of a variable at assignment time.
// Type inference
let str = 'str';
// str = 123; Type "number" cannot be assigned to type "string".
// If no value is assigned, the variable is defined as any and is not type-checked
// The any type allows variables to be changed to any type
Copy the code
The joint type
A union type enables a variable to be one of multiple types.
// union types
// It is defined as number or string, and can only access the common attributes of both types
let numOrStr: number | string;
numOrStr = "123";
numOrStr = 123;
// numOrStr.length; The attribute "length" does not exist on type "number".
Copy the code
Types of assertions
Type assertions use AS to tell the compiler that you know the type better than it does, and to keep it from reporting errors.
// type assertion Type assertion
function getLength(input: string | number) :number {
const str = input as string;
if (str.length) {
return str.length;
} else {
const number = input as number;
return number.toString().length; }}Type assertions are not type conversions and can only be asserted to defined types
Copy the code
Type the guards
Federated types are automatically narrowed down by conditional statements and typeof Instanceof.
// type guard Type guard
function getLength2(input: string | number) :number {
if (typeof input === "string") {
return input.length;
}
else {
// The input of this branch is of type number, intelligently narrowing the scope
returninput.toString().length; }}Copy the code
Class Class
Class basics
-
Class: Defines the abstract characteristics of everything
-
Object: An instance of a class
-
Three characteristics of object-oriented: encapsulation (hide the details of data operations, only expose the interface of the operation), inheritance (subclasses inherit from the parent class, and can have more features), polymorphism (inheritance of different classes can have different responses to the same method)
Class in the TypeScript
-
Three modifiers provide permission management: public (callable anywhere, default), private (not externally callable), and protected (accessible in subclasses)
-
Readonly Read-only property that cannot be modified.
/ / class
class Animal {
readonly name: string;
constructor(name) {
this.name = name
}
run() {
return `The ${this.name} is running`}}/ / object
const snake = new Animal('lily')
// snake.name = 'Joe'; "Name" cannot be assigned because it is a read-only property.
console.log(snake.run()) // lily is running
/ / inheritance
class Dog extends Animal {
bark() {
return `The ${this.name} is barking`}}const xiaobao = new Dog('xiaobao')
console.log(xiaobao.run()) // xiaobao is running
console.log(xiaobao.bark()) // xiaobao is barking
/ / polymorphism
class Cat extends Animal {
static categories = ['mammal'] // Static attributes do not need to be instantiated
constructor(name) {
super(name)
console.log(this.name) // maomao
}
run() {
return 'Meow, ' + super.run()
}
}
const maomao = new Cat('maomao')
console.log(maomao.run()) // Meow, maomao is running
console.log(Cat.categories) // [ 'mammal' ]
Copy the code
Classes and interfaces
-
Inheritance dilemma: A class can only inherit from another class
-
Classes can implement interfaces using implements
interface Radio {
switchRadio(trigger: boolean) :void;
}
interface Battery {
checkBatteryStatus(): void;
}
// Interface inheritance
interface RadioWithBattery extends Radio, Battery {
}
class Car implements Radio {
switchRadio(trigger: boolean) {
// todo...}}// class Cellphone implements Radio, Battery {
class Cellphone implements RadioWithBattery {
switchRadio(trigger: boolean) {
// todo...
}
checkBatteryStatus() {
// todo...}}Copy the code
Enum enumeration
We sometimes use a range of constants whose values can be represented by enumerations.
Numeric enumeration:
// Enumeration of numbers
enum Direction {
// Enumerators are assigned from 0
Up, // (enum member) Direction.Up = 0
Down, // (enum member) Direction.Down = 1
// It can be assigned manually, and the following items will be incremented
Left = 10.// (enum member) Direction.Left = 10
Right, // (enum member) Direction.Right = 11
}
console.log(Direction.Up); / / 0
console.log(Direction[0]); // Up
Copy the code
Compiled js:
var Direction;
(function (Direction) {
// Implement bidirectional assignment
Direction[Direction["Up"] = 0] = "Up";
Direction[Direction["Down"] = 1] = "Down";
Direction[Direction["Left"] = 10] = "Left";
Direction[Direction["Right"] = 11] = "Right";
})(Direction || (Direction = {}));
console.log(Direction.Up);
console.log(Direction[0]);
Copy the code
String enumeration:
String enumeration, used for string comparisons
enum Direction {
Up = 'UP'.// (enum member) Direction.Up = "UP"
Down = 'DOWN',
Left = 'LEFT',
Right = 'RIGHT',}const value = 'UP'
if (value === Direction.Up) {
console.log('go up! ')}Copy the code
var Direction;
(function (Direction) {
Direction["Up"] = "UP";
Direction["Down"] = "DOWN";
Direction["Left"] = "LEFT";
Direction["Right"] = "RIGHT";
})(Direction || (Direction = {}));
var value = 'UP';
if (value === Direction.Up) {
console.log('go up! ');
}
Copy the code
Constant enumeration:
Constant enumerations can improve performance, as the values of the enumerations are compiled directly into the results. Constant enumerations inline any use of enumerations and do not compile the enumerations to JS.
Only const numbers can be enumerated, not computed numbers.
// Constant enumeration to improve performance
const enum Direction {
Up = 'UP',
Down = 'DOWN',
Left = 'LEFT',
Right = 'RIGHT',}const value = 'UP'
if (value === Direction.Up) {
console.log('go up! ')}Copy the code
var value = 'UP';
if (value === "UP" /* Up */) {
console.log('go up! ');
}
Copy the code
Generics generic
Usage of generics
First let’s define a function that returns the argument passed in:
function echo(arg) {
return arg;
}
const result = echo(123); // const result: any
Copy the code
Result is of type any. To make echo’s return value equal and exact to the value passed in, we can use generics.
Generics do not specify types in advance when defining functions, interfaces, and classes, but when they are used.
function echo<T> (arg: T) :T {
return arg;
}
const result = echo('str'); // const result: "STR", type assertion string
Copy the code
// Swap the contents of two items in a tuple
function swap<T.U> (tuple: [T, U]) :U.T] {
return [tuple[1], tuple[0]]}const result2 = swap(['string'.123]) // [123, 'string']
Copy the code
Constraints of generic
If we wanted a function to print the length of an array or string, it would be wrong to write:
function echoWithArr<T> (arg: T) :T {
console.log(arg.length); // Attribute "length" does not exist on type "T".
return arg
}
function echoWithArr2<T> (arg: T[]) :T[] { // Cannot pass string
console.log(arg.length);
return arg
}
Copy the code
We use the extends inheritance interface to constrain generics:
interface IWithLength {
length: number
}
// Uses extends to constrain the passed generic by specifying that it must have a length attribute
function echoWithLength<T extends IWithLength> (arg: T) :T {
console.log(arg.length)
return arg
}
const str = echoWithLength('str')
const obj = echoWithLength({ length: 10.width: 10 })
const arr2 = echoWithLength([1.2.3])
Copy the code
Again, the duck type concept is used as long as the argument has the length attribute.
Application in classes and interfaces
/ / class
class Queue<T> {
private data = [];
push(item: T) {
return this.data.push(item)
}
pop(): T {
return this.data.shift()
}
}
const queue = new Queue<number>()
queue.push(1)
console.log(queue.pop().toFixed())
/ / interface
interface KeyPair<T, U> {
key: T
value: U
}
let kp1: KeyPair<number.string> = { key: 1.value: "string" }
let kp2: KeyPair<string.number> = { key: 'str'.value: 2 }
let arr: number[] = [1.2.3]
// Use generics to declare types
let arr2: Array<number> = [1.2.3]
Copy the code
Type the alias
A type alias is used to define a new name for a type, which is different from interface.
// type aliase Type alias
let sum: (x: number, y: number) = > number;
const result = sum(1.2);
// Create a type alias for the function
type PlusType = (x: number, y: number) = > number;
let sum2: PlusType;
const result2 = sum2(2.3);
// Create a type alias for the object
type Person = { name: string.age: number }
var Jack: Person = { name: "Jack".age: 18 }
// Create a type alias for the union type
type StrOrNumber = string | number;
let result3: StrOrNumber = '123';
result3 = 123;
Copy the code
Type defines an alias for a type, which can be used when crossover or union is needed. Interfaces define unique types, which are used when extends and implements are needed.
literal
Literals can represent not only values but also types, literal types.
// A literal type cannot be assigned to anything other than a type
let str: 'name' = 'name';
// str = 'name1'; Type "name1" cannot be assigned to type "name".
const number: 1 = 1;
// The type alias of the literal type
type Directions = 'Up' | 'Down' | 'Left' | 'Right';
let toWhere: Directions = 'Left';
Copy the code
Cross type
Cross typing is merging multiple types into one type.
// The type alias of the crossover type
interface IName {
name: string
}
type IPerson = IName & { age: number };
let person: IPerson = { name: '123'.age: 123 };
Copy the code
Declaration file
One way to do this with jQuery is to import it directly in HTML with script tags, and then when you use it in TS, TSC has no way of knowing what jQuery is when you use it directly in TS.
jQuery('#id') // can not find the name "jQuery".
Copy the code
Use the DECLARE keyword to tell TSC that the jQuery variable has been defined elsewhere
declare var jQuery: (selector: string) = > any;
jQuery('#id')
Copy the code
Declarations are generally placed in.d.ts files to indicate that the file has a type declaration for TS:
// jQuery.d.ts
declare var jQuery: (selector: string) = > any;
Copy the code
Declare does not define the implementation of a variable, only its type. Used for type checking only.
After that, there will be corresponding code completion and interface prompts when used in other files. Ts parses all ts files in a project. When.d.ts files are placed in a project, all project files have their corresponding type definitions.
When using a third party library, we can use the declaration file of the third party without having to declare it manually.
For example, use the following command to install the jQuery type file:
npm install --save @types/jquery
Copy the code
@types indicates that the file has only type definitions and no concrete implementation.
You can search for the corresponding third party declaration file at the following url:
-
@types Library of official declaration files
-
@types searches the declaration library
Many libraries now come with their own type definitions in the source code, in which case you can just install the source file.
Such as:
npm install --save redux
Copy the code
We can see that node_modules\redux\index.d.ts is the type declaration file.
Built-in types
There are many standard built-in objects in JavaScript. Standard built-in objects are objects that exist in the global scope according to the standard (ECMA, DOM, etc.).
// global object
const a: Array<number> = [1.2.3];
const date: Date = new Date(a); date.getTime();const reg = /abc/;
reg.test("a");
// Unlike other global objects, Math is not a constructor. All properties and methods of Math are static.
Math.pow(2.2);
Copy the code
You can see that these types are defined in multiple places in different files, but they are all part of the internal definition and then merged according to different versions or functions. Multiple definitions of an interface or class are merged together. These files typically start with lib and end with d.ts, indicating that this is a built-in object type.
// DOM and BOM standard objects
// Document object, which returns an HTMLElement
let body: HTMLElement = document.body;
// The document query method returns a nodeList type
let allLis = document.querySelectorAll('li');
// In the callback function, the e event object here also automatically gets the mouseEvent type because of type inference. Since clicking is a mouse event, we can now conveniently use the methods and properties above E.
document.addEventListener('click'.(e) = > {
e.preventDefault()
})
Copy the code
Tool type
Typescript also provides several functional and helpful types. These types, which are not visible in JS, are called utility types and provide some neat and convenient functionality.
// utility types
// partial, which makes all incoming types optional
interface IPerson {
name: string
age: number
}
let Joe: IPerson = { name: 'Joe'.age: 20 }
type IPartial = Partial<IPerson>
let Joe2: IPartial = {}
Omit, which may Omit an attribute of the incoming type
type IOmit = Omit<IPerson, 'name'>
let Joe3: IOmit = { age: 20 }
Copy the code