1. Meet the Typescript

The introduction of TypeScript

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

Microsoft released the first public version of TypeScript in October 2012 and released TypeScript on June 19, 2013 after a preview release

TypeScript was written by anders hejlsberg, the chief architect of C#. It is an open source and cross-platform programming language.

TypeScript extends JavaScript’s syntax so that any existing JavaScript program can run in a TypeScript environment.

TypeScript is designed for large application development and can be compiled into JavaScript.

TypeScript is a superset of JavaScript that provides a type system and support for ES6+. It was developed by Microsoft and its code is opened on GitHub (new Window)

The characteristics of the TypeScript

TypeScript has three main features:

  • It starts with JavaScript and ends with JavaScript

TypeScript compiles clean, concise JavaScript code and runs in any browser, Node.js environment, and any JavaScript engine that supports ECMAScript 3 (or later).

  • 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 offers the latest and evolving JavaScript features, including those from ECMAScript 2015 and future proposals, such as asynchronous functionality and Decorators, to help build robust components.

conclusion

TypeScript is becoming increasingly popular in the community, and it works well on large projects as well as base libraries, greatly improving our development efficiency and experience.

2. Install the 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 -V 
Copy the code

The first TypeScript program

Write TS programs

src/helloworld.ts

function greeter (person) {
  return 'Hello, ' + person
}

let user = 'Yee'

console.log(greeter(user))
Copy the code

Compiling code by hand

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

On the command line, run the TypeScript compiler:

tsc helloworld.ts
Copy the code

The output is a helloworld.js file that contains the same JavsScript code as the input file.

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

node helloworld.js
Copy the code

Console output:

Hello, Yee
Copy the code

Vscode automatically compiles

Json TSC --init 2). Json config "outDir": "./js", "strict": false, 3). Start a monitoring task: Terminal -> Run Task -> Monitor tsconfig.jsonCopy the code

Type annotations

Let’s take a look at the advanced features that TypeScript tools bring. Add a string annotation to the argument to the person function as follows:

function greeter (person: string) {
  return 'Hello, ' + person
}

let user = 'Yee'

console.log(greeter(user))
Copy the 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 take a string argument. Then try passing a call to greeter into an array:

function greeter (person: string) {
  return 'Hello, ' + person
}

let user = [0.1.2]

console.log(greeter(user))
Copy the code

Recompile and you should see an error:

error TS2345: Argument of type 'number[]' is not assignable to parameter of type 'string'.
Copy the code

Similarly, try to remove all arguments to the greeter call. TypeScript tells you that the function was called with an unexpected number of arguments. In both cases, TypeScript provides static code analysis that examines the code structure and provides type annotations.

Note that the greeter.js file was created despite the error. Even if your code has errors, you can still use TypeScript. But in this case, TypeScript warns you that the code may not perform as expected.

interface

Let’s continue to extend the sample application. Here we use an interface to describe an object with firstName and lastName fields. In TypeScript, two types are compatible only if the structure inside them is compatible. This allows us to implement the interface without explicitly using the IMPLEMENTS statement, as long as we ensure that the required structure is included.

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 the code

class

Finally, let’s rewrite this example using classes. TypeScript supports new features of JavaScript, such as 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 compatible.

Also note that I will specify all the member variables in the class declaration so that it is easy to see.

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 the code

Re-run TSC Greeter. ts and you’ll see that the TypeScript class is just a syntactic sugar that is essentially an implementation of JavaScript functions.

conclusion

Now that you have a general idea of TypeScript, let’s take a look at some common TypeScript syntax in the next chapter.

4.Typescript common syntax

The data type

TypeScript supports almost the same data types as JavaScript, and it also provides useful enumerated types for us to use

Personal habit: By default, it is generally not added if the corresponding identifier type can be derived

number

Like JavaScript, all numbers in TypeScript are floating point numbers. These floating point numbers are of type number. In addition to supporting decimal and hexadecimal literals, TypeScript also supports 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 the code

string

String is a string and can be expressed in single or double quotation marks:

let name = "yunmu"
let age = 18

// ES6 template strings are also supported to concatenate variables and strings:
let message3 = `name:${name} age:${age}`
console.log(message3)
Copy the code

boolean

The most basic data types are simple true/false values, called Boolean in JavaScript and TypeScript (and in other languages as well).

let isDone: boolean = false;
isDone = 20 > 30;
Copy the code

Undefined and null

In TypeScript, undefined and null have their own types called undefined and NULL, respectively. Their type by itself is not very useful

let u: undefined = undefined
let n: null = null
// By default null and undefined are subtypes of all types. This means that you can assign null and undefined to variables of type number.
Copy the code

Symbol

In ES5, if we are not allowed to add the same attribute name to the object

But we can also define the same name through symbol, because the symbol function returns a unique value

const title1 = Symbol("title")
const title2 = Symbol('title')

const info = {
  [title1]: "Programmer",
  [title2]: "Teacher"
}
Copy the code

Array

TypeScript, like JavaScript, can manipulate array elements and can be defined in two ways

First, the element type can be followed by [] to represent an array of elements of that 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]  React JSX conflicts with react JSX
Copy the code

If any other type is added to the array, an error is reported

Object

Object means a non-primitive type, that is, a type other than number, string, or Boolean

const obj: object = {
  name: "yunmu".age: 18
}
// Ordinary objects do not have the name attribute, which is best derived from typescript itself
console.log(obj.name)
Copy the code
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 the code

any

In some cases, we can’t really determine the type of a variable, and maybe it will change a bit, so we can use any

We can do anything on a variable of type any, including fetching nonexistent properties and methods

We assign any values to a variable of type any, such as numbers or strings

We can use any in cases where we don’t want to add a specified type annotation, or where a type annotation is missing when we introduce some third-party libraries

let message: any = "Hello World"

message = 123
message = true
message = {
}
message() / / an error
message.toUpperCase()
const arr: any[] = []
Copy the code

unknown

Unknown is a special type in TypeScript that describes variables of uncertain type

function foo() {
    return "abc";
}

function bar() {
    return 123;
}

// The unknown type can only be assigned to any and unknown types
The any type can be assigned to any type
let flag = true;
let result: unknown; // It is best not to use any
if (flag) {
    result = foo();
} else {
    result = bar();
}
// An error is reported if any is not used
let message: string = result;
let num: number = result;

console.log(result);
Copy the code

void

Void is usually used to specify that a function has no return value, so its return value is void

  • We can assign null and undefined to void, which means functions can return either null or undefined
// The function returns void by default
function sum(num1: number, num2: number) :void {
  console.log(num1 + num2);
}
Copy the code

never

Never indicates the type of value that never occurs, such as a function

If a function is in an infinite loop or throws an exception, does the function return something?

function foo() :never {
  / / death cycle
  while(true) {}}// Throw an error
function bar() :never {
  throw new Error()}function handleMessage(message: string | number | boolean) {
  switch (typeof message) {
    case "string":
      console.log("String processing for message");
      break;
    case "number":
      console.log("Number processing to handle message");
      break;
    case "boolean":
      console.log("Boolean processing method handles message");
      break;
    default:
      const check: never= message; }}// The function that passes any other type will assign never to an error
handleMessage("abc");
handleMessage(123);
handleMessage(true);
Copy the code

tuple

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

const info: [string.number] = ["hello".10];
info = ["yunmu".18];
// When accessing an element with a known index, the correct type is obtained:
const name = info[0];
Copy the code

Application:

function useState<T> (state: T) :T, (newState: T) = >void] {
  let currentState = state;
  const changeState = (newState: T) = > {
    currentState = newState;
  };
  // const info: [string, number] = ["abc", 18];
  const tuple: [T, (newState: T) = > void] = [currentState, changeState];
  return tuple;
}

const [counter, setCounter] = useState(10);
setCounter(1000);
const [title, setTitle] = useState("abc");
const [flag, setFlag] = useState(true);
Copy the code

Enumerated type

Enumeration types are used to give friendly names to a set of values

Enumerations allow developers to define a set of named constants, which can be numbers or strings

enum Color {
  Red,
  Green,
  Blue
}

// Enumeration values start at 0 by default
// Get the corresponding enumeration value based on the specific name
let myColor: Color = Color.Green  / / 0
console.log(myColor, Color.Red, Color.Blue)
Copy the code

By default, elements are numbered from 0. You can also manually specify the values of the members

Let’s change the above example to number from 1:

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

Alternatively, all manual assignments are used:

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

One of the conveniences provided by an enumerated type is that you can refer to its name by enumeration

For example, if we know that the value is 2, but are not sure which name it maps to in Color, we can look up the corresponding name

enum Color {Red = 1, Green, Blue}
let colorName: string = Color[2]

console.log(colorName)  // 'Green'
Copy the code
enum Direction {
  LEFT = "LEFT",
  RIGHT = "RIGHT",
  TOP = "TOP",
  BOTTOM = "BOTTOM",}function turnDirection(direction: Direction) {
  switch (direction) {
    case Direction.LEFT:
      console.log("Change the character's direction to the left.");
      break;
    case Direction.RIGHT:
      console.log("Change the direction of the character to the right.");
      break;
    case Direction.TOP:
      console.log("Change the direction of the character up.");
      break;
    case Direction.BOTTOM:
      console.log("Change the direction of the character downward.");
      break;
    default:
      const foo: never = direction;
      break;
  }
}

turnDirection(Direction.LEFT);
turnDirection(Direction.RIGHT);
turnDirection(Direction.TOP);
turnDirection(Direction.BOTTOM);
Copy the code

Function parameter and return value types

TypeScript allows us to specify the types of function arguments and return values

Annotate function arguments with type: num1: number, num2: number

function sum(num1: number, num2: number) {
  return num1 + num2;
}

sum(123); / / an error
Copy the code

Comment the return value with a type comment: (): number. In development, it is usually possible to omit the type of the return value (automatic derivation).

function sum(num1: number, num2: number) :number {
  return num1 + num2;
}
Copy the code

Anonymous functions are a little different from function declarations. When a function appears in a place where TypeScript can determine how the function will be called, the function’s parameters are automatically typed, right

const names = ["abc"."cba"."nba"];
// item is a string derived from the context in which the function is executed. Type annotations can be omitted because the context in which the function is executed helps determine the type of the argument and return value
names.forEach(function (item) {
  console.log(item.split(""));
});
Copy the code

Object type

Sometimes we want a function to take an object as an argument

We use object types

Can we add an attribute to an object and tell TypeScript what type the attribute needs to be, or any if not specified

Attributes can be used between, or; The last delimiter is optional

function printPoint(point: { x: number; y: number }) {
  console.log(point.x);
  console.log(point.y);
}

printPoint({ x: 123.y: 321 });
Copy the code

The object type can also specify which attributes are optional. Can you add one after the attribute?

function printPoint(point: { x: number; y: number; z? :number }) {
  console.log(point.x);
  console.log(point.y);
  console.log(point.z);
}

printPoint({ x: 123.y: 321 });
printPoint({ x: 123.y: 321.z: 111 });
Copy the code

The joint type

TypeScript’s type system allows us to build new types from existing types using multiple operators

The first way to combine types is Union types

  • A union type is a type composed of two or more other types that can represent a value of any one of them
  • Each of the union types is called union’s members.
/ / number | string | Boolean joint type
function printID(id: number | string | boolean) {
    console.log(id);
}
Copy the code

Be careful when using union types, because we may get different types of values

For example, if we get a number, we can’t call a string method

We can use narrow associations to infer more specific types

function printID(id: number | string | boolean) {
  Use special care when using values of union types
  / / narrow, narrow
  if (typeof id === "string") {
    // TypeScript helps determine that the ID must be a string
    console.log(id.toUpperCase());
  } else {
    console.log(id);
  }
}
printID(123);
printID("abc");
printID(true);
Copy the code

The relationship between optional types and union types

/ / a parameter to an optional type, it is similar and the parameter is the type | undefined type of joint
function foo(message? :string) {
  console.log(message)
}
Copy the code

Type the alias

We used to write objects and union types through type annotations, and it was a bit cumbersome to use the same type multiple times

We can define a type alias using type.

type IDType = string | number | boolean;
type PointType = {
  x: number;
  y: number; z? :number;
};

function printId(id: IDType) {}

function printPoint(point: PointType) {}
Copy the code

Type assertion AS

Sometimes TypeScript cannot get specific Type information; we need to use Type Assertions.

For example, with Document.getelementById, TypeScript only knows that this function returns HTMLElement, but it doesn’t know its type

const el = document.getElementById("yun") as HTMLImageElement;
el.src = "Url";
Copy the code
// Person is the parent of Student
class Person {}

class Student extends Person {
  studying(){}}function sayHello(p: Person) {
  (p as Student).studying();
}

const stu = new Student();
sayHello(stu);
Copy the code

Type inference

Type inference: TS will infer a type when no explicit type is specified

There are two cases: 1. When defining a variable, it is assigned to the corresponding type. 2. The variable is defined without an assignment and is inferred to be of type any

/* The variable is assigned to the corresponding type */
let b9 = 123 // number
// b9 = 'abc' // error

/* The variable is defined without an assignment and is inferred to be of type any */
let b10  / / any type
b10 = 123
b10 = 'abc'
Copy the code

Non-null type assertion!

We can use non-null type assertions when we are sure that the parameter passed in has a value

Non-empty assertions use! , indicating that an identifier can be determined to have a value, skipping ts’s detection of it at compile time

function printMessageLength(message? :string) {
  // if (message) {
  // console.log(message.length)
  // }
  console.log(message! .length); }Copy the code

Optional chain

It is an added feature in ES11 (ES2020)

Optional chain using optional chain operator? .

If the property of the object does not exist, it will short-circuit and return undefined. If it exists, execution will continue

type Person = {
  name: string; friend? : {name: string; age? :number; girlFriend? : {name: string;
    };
  };
};

const info: Person = {
  name: "yun".friend: {
    name: "kobe".girlFriend: {
      name: "lily",}}};console.log(info.friend?.name);
console.log(info.friend?.age);
console.log(info.friend?.girlFriend?.name);
Copy the code

?? And!!!!! The operator

!!!!! The operator

To cast an additional type to a Boolean type, in a manner similar to Boolean(variables)

?? The operator

It is a new feature in ES11 that returns the right-hand operand if the left-hand side of an operator is null or undefined, otherwise returns the left-hand operand

constflag = !! message;console.log(flag);
let message: string | null = "Hello World";

const content = message ?? "Hello, Yunmu.";
console.log(content);
Copy the code

Literal type

// "Hello World" can also be a type, called a literal type
const message: "Hello World" = "Hello World";

// The meaning of literal types is that union types must be combined
type Alignment = "left" | "right" | "center";
let align: Alignment = "left";
align = "right";
align = "center";
Copy the code

Literal reasoning

Let’s look at the following code

type Method = "GET" | "POST";
function request(url: string, method: Method) {}

const options = {
  url: "https://www.coderwhy.org/abc".method: "POST",}as const;

request(options.url, options.method);
Copy the code

Method: {url: string, method: string}}, so we can’t assign a string to a literal type

A:

type Request = {
  url: string;
  method: Method;
};

constOptions: Request = {url: "https://www.coderwhy.org/abc".method: "POST"};Copy the code

Method 2:

request(options.url, options.method as Method);
Copy the code

Three:

const options = {
  url: "https://www.coderwhy.org/abc".method: "POST",}as const
Copy the code

Type to reduce the

Type Narrowing.

We can change TypeScript execution paths with typeof padding === “number” statements

Will be able to shrink a smaller type in a given path than when declared, the process is called narrowing

And typeof padding === “number is called type Guards.

Common type protection

  • typeof
  • Equality diminishes (e.g. ===,! = =)
  • instanceof
  • in

typeof

You can operate on different values using typeof check types

type IDType = number | string;
function printID(id: IDType) {
  if (typeof id === "string") {
    console.log(id.toUpperCase());
  } else {
    console.log(id); }}Copy the code

Equal to narrow

We can use Switch or some equality operator to express equality (such as ===, ==,! = =,! =)

type Direction = "left" | "right" | "top" | "bottom";
function printDirection(direction: Direction) {
  / / 1. If judgment
  if (direction === 'left') {
    console.log(direction)
  } else if(a)/ / 2. The switch of judgment
  switch (direction) {
    case 'left':
      console.log(direction)
      break;
    case. }}Copy the code

instanceof

Operator to check whether a value is an instance of another value

function printTime(time: string | Date) {
  if (time instanceof Date) {
    console.log(time.toUTCString());
  } else {
    console.log(time); }}Copy the code
class Student {
  studying(){}}class Teacher {
  teaching(){}}function work(p: Student | Teacher) {
  if (p instanceof Student) {
    p.studying();
  } else{ p.teaching(); }}const stu = new Student();
work(stu);
Copy the code

in

The IN operator is used to determine that the specified property is in the specified object or its stereotype chain, and returns true

type Fish = {
  swimming: () = > void;
};

type Dog = {
  running: () = > void;
};

function move(animal: Fish | Dog) {
  if ("swimming" in animal) {
    animal.swimming();
  } else{ animal.running(); }}const fish: Fish = {
  swimming() {
    console.log("swimming"); }}; move(fish);Copy the code

TypeScript function types

Functions are very common in Javascript, even first-class citizens (passed as arguments or return values)

In TypeScript we can write Function Type Expressions to represent Function types

1. When a function is used as a parameter, write a type in the parameter

function foo() {}

type FooFnType = () = > void;
function bar(fn: FooFnType) {
  fn();
}

bar(foo);
Copy the code

2. Write the type of the function when defining constants

// (num1: number, num2: number) => number
// A function that takes two arguments: num1 and num2, both of type number
// Return number again
type AddFnType = (num1: number, num2: number) = > number;
const add: AddFnType = (a1: number, a2: number) = > {
  return a1 + a2;
};
Copy the code

Optional type of argument

// Optional types must be written after required types
function foo(x: number, y? :number) {}

foo(20.30);
foo(20);
Copy the code

The default parameters

General Order Mandatory parameters – Parameters with default values – Optional parameters

function foo(y: number, x: number = 20) {
  console.log(x, y);
}

foo(30);
Copy the code

The remaining parameters

The residual argument syntax allows us to put an indefinite number of arguments into an array

function sum(initalNum: number. nums:number[]) {
  let total = initalNum;
  for (const num of nums) {
    total += num;
  }
  return total;
}

console.log(sum(20.30));
console.log(sum(20.30.40));
console.log(sum(20.30.40.50));
Copy the code

This type of

This is a Javascript keyword that binds different values in different contexts

By default, this can be derived

const info = {
  name: "yunmu".eating() {
    console.log(this.name + " eating")
  }
}

info.eating()
Copy the code

We can also specify this

type ThisType = { name: string };

function eating(this: ThisType, message: string) {
  console.log(this.name + " eating", message);
}

const info = {
  name: "why".eating: eating,
};

// Implicit binding
info.eating("Ha ha ha.");

// Show the binding
eating.call({ name: "kobe" }, "Hehe hehe");
eating.apply({ name: "james"},"Hey hey hey."]);
Copy the code

Function overloading

What if we wrote an add function that wanted to add string and number types?

function add(a1: number | string, a2: number | string) {
   return a1 + a2;  / / an error
}
Copy the code

Solution 1: Union type

function add(a1: number | string, a2: number | string) {
  if (typeof a1 === "number" && typeof a2 === "number") {
    return a1 + a2;
  } else if (typeof a1 === "string" && typeof a2 === "string") {
    return a1 + a2;
  }
}

add(10.20);
/** * There are two disadvantages to combining types: * 1. A lot of logical judgment (type narrowing) * 2. The type of the return value is still undetermined */
Copy the code

Solution 2: function overload

Multiple functions with the same name but different parameters are overloaded functions

We can write different overload signatures to indicate that functions can be called in different ways

It is common to write two or more overloaded signatures and then write a generic function implementation

function add(num1: number, num2: number) :number; // No function body
function add(num1: string, num2: string) :string;

function add(num1: any, num2: any) :any {
  if (typeof num1 === "string" && typeof num2 === "string") {
    return num1.length + num2.length;
  }
  return num1 + num2;
}

const result1 = add(20.30);
const result2 = add("abc"."cba");
console.log(result1);
console.log(result2);


Copy the code

In function overloading, the implementation function cannot be called directly

Combine types and overloads

We now have a requirement to define a function that can pass in strings or arrays and get their lengths

As above, there are two implementations

Scheme 1: Combination type

function getLength(args: string | any[]) {
  return args.length
}
console.log(getLength("abc"))
console.log(getLength([123.321.123]))
Copy the code

Scheme 2: function overloading

function getLength(args: string) :number;
function getLength(args: any[]) :number;
function getLength(args: any) :number {
  return args.length;
}

console.log(getLength("abc"));
console.log(getLength([123.321.123]));
Copy the code

In development, select federated types whenever possible

Class in the Typescript

Before ES6 we needed to implement classes and inheritance through a chain of functions and stereotypes

Starting with ES6, the class keyword was introduced to make it easier to define classes and inheritance

In practice, though, we use more functional programming ideas

But classes are also very encapsulation, and we need to master it

The definition of a class

We usually use the class keyword to define a class

In the object-oriented world, anything can be described using the structure of a class

Classes contain unique properties and methods

Let’s define a Person class using class

We can declare the attributes of a class and their corresponding types inside the class. No declaration, default is any

In the default strictPropertyInitialization mode, we must can give attribute set initialization values

If the implementation doesn’t want to use name! : Syntax for string

The class has its own constructor, called when we create an instance with the new keyword

Classes can have their own functions, defined functions called methods

class Person { name! :string;
  age: number;

  constructor(name: string, age: number) {
    // this.name = name;
    this.age = age;
  }

  eating() {
    console.log(this.name + " eating"); }}const p = new Person("yun".18);
console.log(p.name);
console.log(p.age);
p.eating();
Copy the code

Class inheritance

One of the features of object orientation is inheritance, which can not only reduce the amount of code we use, but also the premise of using polymorphism

We use the extends keyword for inheritance and super in subclasses to access the parent class

Let’s look at the Student class inheriting from Person

The Student class can have its own properties and methods, and will inherit the properties and methods of Person

In the constructor, we can call the constructor of the parent class with super to initialize the properties in the parent class

class Person {
  name: string
  age: number

  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }

  eating() {
    console.log("Eating 100 line")}}class Student extends Person {
  sex: number

  constructor(name: string, age: number, sex: number) {
    // super calls the constructor of the parent class
    super(name, age)
    this.sex = sex
  }

  eating() {
    console.log("student eating")
    super.eating()
  }

  studying() {
    console.log("studying")}}const stu = new Student("yun".18.111)
console.log(stu.name)
console.log(stu.age)
console.log(stu.sex)
stu.eating()
Copy the code

Class of polymorphism

Polymorphic premise: A reference to a parent class refers to a subclass object

It looks like the same type, but the method is not the same

class Animal {
  action() {
    console.log("animal action"); }}class Dog extends Animal {
  action() {
    console.log("dog running!!!"); }}class Fish extends Animal {
  action() {
    console.log("fish swimming"); }}// animal: dog/fish
// The purpose of polymorphism is to write more universal code
function makeActions(animals: Animal[]) {
  animals.forEach((animal) = > {
    animal.action();
  });
}

makeActions([new Dog(), new Fish(), new Person()]);
Copy the code

Class member modifier

In TypeScript, class properties and methods support three modifiers: public, private, and protected

  • Public modifies properties or methods that are public and visible anywhere, and properties written by default are public
  • Private modifies properties or methods that are visible only in the same class and are private
  • Protected modifies the properties or methods that are visible and protected only in the class itself and its subclasses

private

class Person {
  private name: string = "";
  // Encapsulates two methods that access name
  getName() {
    return this.name;
  }
  setName(newName) {
    this.name = newName; }}const p = new Person();
console.log(p.getName());
p.setName("yun");
Copy the code

protected

// protected: Accessible within the class and in subclasses
class Person {
  protected name: string = "123";
}

class Student extends Person {
  getName() {
    return this.name; }}const stu = new Student();
console.log(stu.getName());
Copy the code

Read-only property readonly

If you have an attribute that you don’t want the outside world to modify arbitrarily, but only want to use after fixing the value, you can use readonly

class Person {
  // 1. Read-only attributes can be assigned in the constructor and cannot be modified after assignment
  // 2. The attribute itself cannot be modified, but if it is an object type, the attribute in the object can be modified
  readonly name: string; age? :number;
  readonlyfriend? : Person;constructor(name: string, friend? : Person) {
    this.name = name;
    this.friend = friend; }}const p = new Person("yun".new Person("kobe"));
console.log(p.name);
console.log(p.friend);

// You cannot change friend directly
// p.friend = new Person("james")
if (p.friend) {
  p.friend.age = 30;
}
Copy the code

getters/setters

Before, we had some private properties that we couldn’t access directly, and some properties that we wanted to listen to for getters and setters, so we could use accessors

class Person {
  private _name: string;
  constructor(name: string) {
    this._name = name;
  }
  // Accessor setter/getter
  // setter
  set name(newName) {
    this._name = newName;
  }
  // getter
  get name() {
    return this._name; }}const p = new Person("yun");
p.name = "yunmu";
console.log(p.name);
Copy the code

Static members

The members and methods we defined in the class above are at the object level

In development, we also sometimes need to define members and methods at the class level

Defined in TypeScript with the static keyword

class Student {
  static time: string = "PM";

  static attendClass() {
    console.log("To learn."); }}console.log(Student.time);
Student.attendClass();
Copy the code

An abstract class abstract

Inheritance is a prerequisite for the use of polymorphism

So when defining a lot of generic calling interfaces, we usually let the caller pass in the parent class to make the call more flexible through polymorphism

However, the parent class itself may not need to implement specific methods, so methods defined in the parent class can be defined as abstract methods

What are abstract methods? Methods that are not implemented in TypeScript (without a method body) are abstract methods

  • Abstract methods must exist in abstract classes
  • Abstract classes are classes that use abstract declarations

Abstract classes have the following characteristics

  • Abstract classes cannot be instantiated (that is, cannot be created by new)
  • Abstract methods must be implemented by subclasses
function makeArea(shape: Shape) {
  return shape.getArea();
}

abstract class Shape {
  abstract getArea(): number;
}

class Rectangle extends Shape {
  private width: number;
  private height: number;

  constructor(width: number, height: number) {
    super(a);this.width = width;
    this.height = height;
  }

  getArea() {
    return this.width * this.height; }}class Circle extends Shape {
  private r: number;

  constructor(r: number) {
    super(a);this.r = r;
  }

  getArea() {
    return this.r * this.r * 3.14; }}const rectangle = new Rectangle(20.30);
const circle = new Circle(10);

console.log(makeArea(rectangle));
console.log(makeArea(circle));
// All the following errors are reported
// makeArea(new Shape())
// makeArea(123)
// makeArea("123")
Copy the code

The type of the class

Classes themselves can also be a data type

class Person {
  name: string = "123";
  eating(){}}const p = new Person(); / / the Person type

const p1: Person = {
  name: "yun".eating(){}};function printPerson(p: Person) {
  console.log(p.name);
}

printPerson(new Person());
printPerson({ name: "kobe".eating: function () {}});Copy the code

interface

Declaration of interfaces

We can declare object types through type aliases

type InfoType = {name: string.age: number}
Copy the code

You can also use an interface

interface IInfoType {
  name: string;
  age: number;
}

const info: IInfoType = {
  name: "yun".age: 18};Copy the code

Optional attribute

We can also define optional attributes in the interface

interface IInfoType {
  name: string; age? :number; friend? : {name: string;
  };
}

const info: IInfoType = {
  name: "yun".age: 18.friend: {
    name: "kobe",}};console.log(info.friend?.name);
Copy the code

Read-only property

Read-only attributes can also be defined in an interface

This means that the value cannot be changed after initialization

interface IInfoType {
  readonly name: string;
  age: number;
  readonly friend: {
    name: string;
  };
}
const info: IInfoType = {
  name: "why".age: 18.friend: {
    name: "kobe",}}; info.name ="123" / / an error
info.friend = {} / / an error
info.friend.name = "yunmu" // OK
Copy the code

The index type

The interface was used to define the object type, where the property name, type, and method are defined

// Use interface to define index type index
interface IndexLanguage {
  [index: number] :string
}

const frontLanguage: IndexLanguage = {
  0: "HTML".1: "CSS".2: "JavaScript".3: "Vue"
}


interface ILanguageYear {
  [name: string] :number
}

const languageYear: ILanguageYear = {
  "C": 1972."Java": 1995."JavaScript": 1996."TypeScript": 2014
}
Copy the code

Function types

Interfaces are used to define common attributes and methods in objects, but they can also be used to define function types

// Callable interface
interface CalcFn {
  (n1: number.n2: number) :number;
}

function calc(num1: number, num2: number, calcFn: CalcFn) {
  return calcFn(num1, num2);
}

const add: CalcFn = (num1, num2) = > {
  return num1 + num2;
};

calc(20.30, add);
Copy the code

Of course, it is generally recommended that you use type aliases to define functions

type CalcFn = (n1: number, n2: number) = > number
Copy the code

Interface inheritance

Interfaces, like classes, can be inherited using the extends keyword

And interfaces support multiple inheritance (classes do not)

interface ISwim {
  swimming: () = > void;
}

interface IFly {
  flying: () = > void;
}

interface IAction extends ISwim, IFly {}

const action: IAction = {
  swimming() {},
  flying(){}};Copy the code

Interface implementation

Once an interface is defined, it can be implemented by a class

If an interface is implemented by a class, that class can be passed in wherever the interface needs to be passed in later

This is called interface oriented development

Cross type

The union type you learned earlier represents just one of several types

  • type MyType = number | string
  • type Direction = "left" | "right" | "center"

Intersection Types There is another type of merge, called Intersection Types.

  • Cross similarity means that conditions of more than one type need to be satisfied
  • Cross similarity means that conditions of more than one type need to be satisfied

The following cross type satisfies both a number and a string, but it does not, so MyType is actually a never type

type MyType = number & string
Copy the code

So in development, when we do crossovers, we usually do crossovers for object types

interface ISwim {
  swimming: () = > void;
}

interface IFly {
  flying: () = > void;
}

type MyType1 = ISwim | IFly;
type MyType2 = ISwim & IFly;

const obj1: MyType1 = {
  flying(){}};const obj2: MyType2 = {
  swimming() {},
  flying(){}};Copy the code

Interface is different from type

Interface and type can both be used to define object types, so which one to choose when defining object types in development?

If you are defining non-object types,

  • It is recommended to usetype, such as Direction, Alignment, Function

If you define object types, they are different

  • Interfaces can repeatedly define properties and methods for an interface (equivalent to merging interfaces)

    interface IFoo {
      name: string
    }
    
    interface IFoo {
      age: number
    }
    Copy the code
  • Type defines an alias, which cannot be repeated

    / / an error
    type IBar = {
      name: string
      age: number
    }
      
    type IBar = { 
    }
    Copy the code

Literal assignment

TypeScript imposes strict type restrictions for type derivation when assigning literal values directly

If we are assigning a variable identifier to another variable, a freshness erase is performed

interface IPerson {
  name: string;
  age: number;
  height: number;
}

const info = {
  name: "why".age: 18.height: 1.88.address: "Guangzhou"};// freshness erases assignment to p erases unnecessary address attributes
const p: IPerson = info;

console.log(info);
console.log(p);
Copy the code

Type erasure occurs when we pass a reference to a function as an argument

function printInfo(person: IPerson) {
  console.log(person);
}

const info = {
  name: "yun".age: 18.height: 1.88.address: "Guangzhou"}; printInfo(info);Copy the code

The generic

A feature that does not specify a specific type when defining a function, interface, or class, but specifies the specific type when it is used

Generics implement type parameterization

When defining this function, I do not determine the types of these arguments

I’m going to let the caller tell me, in terms of parameters, what type of function arguments should I have here

function sum<Type> (num: Type) :Type {
  return num;
}
// Call method 1: pass the type to the function by < type >
sum<number> (20);
sum<{ name: string({} >name: "why" });
sum<any[] > ["abc"]);

Type inference, which automatically extrapolates to the type of the variable we pass in
sum(50);
sum("abc");
Copy the code

Generics accept multiple type parameters

function foo<T.E.O> (arg1: T, arg2: E, arg3? : O, ... args: T[]) {
}

foo<number.string.boolean> (10."abc".true)
Copy the code

You might see some common names in development

  • T: short for Type
  • K, V: short for key and value, key-value pair
  • E: Short for Element
  • O: Object

A generic interface

We can also use generics when defining interfaces

Specify default values

interface iFoo<T = number> {

}
Copy the code

Use of generic classes

class Point<T> {
  x: T;
  y: T;
  z: T;

  constructor(x: T, y: T, z: T) {
    this.x = x;
    this.y = y;
    this.z = y; }}const p1 = new Point("1.33.2"."2.22.3"."4.22.1");
const p2 = new Point<string> ("1.33.2"."2.22.3"."4.22.1");
const p3: Point<string> = new Point("1.33.2"."2.22.3"."4.22.1");

const names2: Array<string> = ["abc"."cba"."nba"]; // React JSX is not recommended.
const names1: string[] = ["abc"."cba"."nba"];
Copy the code

Generic constraints for a type

Sometimes we want the types passed in to have some commonality, but those commonalities may not be in the same type

For example, string and array have length, or some objects have length

So as long as the length of the property can be used as our parameter type, so how to operate?

interface ILength {
  length: number;
}

function getLength<T extends ILength> (arg: T) {
  return arg.length;
}

getLength("abc");
getLength(["abc"."cba"]);
getLength({ length: 100 });
Copy the code

Modular development

TypeScript supports two ways to control our scope

  • Modularity: Each file can be a separate Module, supporting ES Module as well as CommonJS
  • Namespace: A namespace is declared through a namespace
export function add(num1: number, num2: number) {
  return num1 + num2;
}

export function sub(num1: number, num2: number) {
  return num1 - num2;
}
Copy the code

Namespace namespace

In TypeScript’s early days, namespaces were called internal modules

The main purpose is to divide the scope within a module to prevent some naming conflicts

export namespace time {
  export function format(time: string) {
    return "2222-02-22";
  }
  export let name: string = "abc";
}

export namespace price {
  export function format(price: number) {
    return "99.99"; }}Copy the code

Type declaration

Type lookup

We’ve written almost all of the typescript types in the past, but we also use some other types

Const imageEl = document.getelementById (“image”) as HTMLImageElement;

Where does the HTMLImageElement type come from?

This is where typescript’s rules for managing and finding types come in

Typescript also has another type of file,.d.ts files, that declare what types are available

So where does typescript look for our type declarations?

  • Built-in type declaration
  • Externally define type declarations
  • Externally define type declarations

Built-in objects

There are many built-in objects in JavaScript that can be treated directly as defined types in TypeScript

Built-in objects are objects that exist in the Global scope according to the standard. Standards here refer to ECMAScript and standards in other environments such as DOM

  1. ECMAScript built-in object
  • Boolean
  • Number
  • String
  • Date
  • RegExp
  • Error
/* 1. ECMAScript built-in objects */
let b: Boolean = new Boolean(1)
let n: Number = new Number(true)
let s: String = new String('abc')
let d: Date = new Date(a)let r: RegExp = / / ^ 1
let e: Error = new Error('error message')
b = true
// let bb: boolean = new Boolean(2) // error
Copy the code
  1. BOM and DOM built-in objects
  • 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 the code

Built-in type declaration

Built-in type declarations are the declarations that come with typescript that help us build in some of the JavaScript runtime’s standardized apis

This includes built-in types such as Math and Date, as well as DOM apis such as Window and Document

Built-in type declarations usually come with typescript installations

  • · Microsoft /TypeScript (github.com)

Externally define type declarations

External type declarations are usually used when we use some library (such as third-party library), we need to reference its declaration file, in order to get the corresponding code completion, interface hints and other functions

These libraries typically have two types of declarations:

  • Method 1: Make type declarations in your own library (write.d.ts files), such as Axios
  • Method 2: A DefinitelyTyped public library of the community stores the type declaration file
    • GitHub address for the library: github.com/DefinitelyT…
    • The library search statement installation address: www.typescriptlang.org/dt/search?s…
    • For example, we install the react type declaration: NPM i@types /react –save-dev

Custom declaration

When do you need to define a declaration file yourself?

  • Case 1: The third-party library we use is a pure JavaScript library with no corresponding declaration file. Such as lodash
  • Case 2: We declare some types in our code so we can use them directly elsewhere

The statement module

We can also declare modules, such as loDash, if the module is disabled by default. We can declare the module ourselves

Declare module ‘module name’ {}

In the declaration module, we can export the corresponding library classes, functions and so on

declare module "lodash" {
  export function join(arr: any[]) :any;
}
Copy the code

Declare variable-function-class

// index.html
let whyName = "coderwhy";
let whyAge = 18;
let whyHeight = 1.88;

function Foo() {
    console.log("whyFoo");
}

function Person(name, age) {
    this.name = name;
    this.age = age;
}

// .d.ts
// Declare variables/functions/classes
declare let whyName: string;
declare let whyAge: number;
declare let whyHeight: number;

declare function whyFoo() :void;

declare class Person {
  name: string;
  age: number;
  constructor(name: string, age: number);
}
Copy the code

Declare declaration file

In some cases, we can also declare files

For example, during vUE development, our.vue files are not recognized by default, so we need to file them

For example, we use image files like.jpg in development, which are not supported by the default typescript and need to be declared

declare module "*.vue" {
  import { DefineComponent } from "vue";
  const component: DefineComponent;
  export default component;
}

declare module "*.jpg" {
  const src: string;
  export default src;
}
Copy the code

Declare namespace

For example, we introduced jQuery directly in index. HTML

  • CDN address: cdn.bootcdn.net/ajax/libs/j…

We can make namespace declarations:

declare namespaceThe ${export function ajax(settings: any) :any;
}
Copy the code

This can be used in main.ts:

$.ajax({
  url: "http://123.207.32.32:8000/home/multidata".success: (res: any) = > {
    console.log(res); }});Copy the code

Tsconfig. Json file

Tsconfig. json is a configuration option used to configure TypeScript compile-time

TypeScript: TSConfig Reference – Docs on every TSConfig option (typescriptlang.org)

5. Pack TS with Webpack

Download the dependent

yarn add -D typescript
yarn add -D webpack webpack-cli
yarn add -D webpack-dev-server
yarn add -D html-webpack-plugin clean-webpack-plugin
yarn add -D ts-loader
yarn add -D cross-env
Copy the code

#JS: entrance SRC/main. Ts

// import './01_helloworld'

document.write('Hello Webpack TS! ')
Copy the code

#Index page: public/index.html

<! DOCTYPEhtml>
<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 the 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' // Whether the 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 error information
    port: 8081.open: true}},Copy the code

#Configuring 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 the code

#Run and package

yarn dev
yarn build
Copy the code