TypeScript learning notes

7,Typescript

Official documents

Atwood's law

Jeff Atwood, one of the founders of Stack Overflow, put forward the famous Atwood law in 2007

any application that can be written in JavaScript , will eventually be written in JavaScript.

Any application that can be implemented using JavaScript will eventually be implemented using JavaScript

  • web side
  • Mobile terminal RN uni
  • Applet side
  • Desktop electron ic
  • Server side node

Type detection is missing, which can easily lead to code crash and so on

7.1 type constraints

In order to make up for the defects of JavaScript type constraints and add type constraints, many companies have launched their own solutions

In 2014, Facebook launched flow to type check JavaScript

In the same year, Microsoft also launched typescript version 1.0

vue2.x uses flow for type checking

vue3.x uses TS

7.2 understanding TypeScript

TS is a js superset with types, which can be compiled into ordinary, clean and complete js code

It starts with JavaScript and ends with JavaScript

TS starts with the syntax and semantics familiar to millions of JS developers today. Use the existing JS code, including the popular JS library, and call TS code from JS code.

TS code can compile pure and concise JS code, and can run on any browser and node JS environment, any JS engine that supports ECMAScript 3 (or higher)

TS is a powerful tool for building large projects

  • Type allows JS developers to use efficient development tools and common operations, such as static checking and code refactoring, when developing JS applications
  • Type is optional. Type inference allows some type comments to make a big difference in the static verification of your code. Types allow you to define interfaces between software components and gain insight into the behavior of existing JS libraries

Advanced JS

  • TypeScript provides the latest and evolving JavaScript features, including those from ECMAScript in 2015 and features in future proposals, such as asynchronous functions and Decorators, to help build robust components;
  • These features are available when developing highly trusted applications, but will be compiled into concise ECMAScript3 (or later) JavaScript;

Many projects adopt TS

  • angular
  • vue3
  • vscode
  • Ant design UI Library
  • At present, Vue3+TS react+ts is popular in the company
  • Applets also support TS

7.3 TS compilation environment

As mentioned earlier, TypeScript will eventually be compiled into JavaScript to run, so we need to build a corresponding environment: we need to install TypeScript on the computer so that we can compile it into JavaScript through the TypeScript Compiler;

# Installation command
npm install typescript -g
# Check the version number January 21, 2022. The version number is Version 4.5.5
tsc --version

7.4 TS operating environment

Scheme I

  1. The first step is to compile TS to JS code through tsc
  2. The second step is to run JS code in the browser or Node environment

Scheme II

Through webpack, configure the local TypeScript compilation environment and start a local service, which can run directly on the browser;

Deployment article link

Scheme III

Provide execution environment for TypeScript running through TS node library;

# Install TS node
npm install ts-node -g
# In addition, TS node also needs to install tslib and @ types/node packages
npm install tslib @types/node -g
# Now you can run TS suffix files directly through TS node
ts-node math.ts

Tip: when writing ts, by default, all TS files are compiled under one scope, so they may conflict. If you want to treat each file as a separate scope, you need to add export {} at the end of each file. There are other solutions

7.5 declaration of TS variables

After declaring a type, TypeScript will carry out type detection. The declared type can be called type annotation

var/let/const identifier : data type = assignment;

Note: the string here is lowercase, which is different from string. String is the string type defined in TypeScript and string is a class defined in ECMAScript

Type derivation: in development, sometimes for convenience, we do not write the corresponding data type when declaring each variable. We prefer to use the characteristics of TypeScript to help us infer the corresponding variable type:

let message = "ddg"
message = 123 // In fact, there will be errors here

This is because when a variable is assigned for the first time, the type of the variable will be inferred according to the type of the later assignment content

7.6 data types of TS and JS

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-oaildhyf-1643279385255) (codewhy-vue3-componentization. assets/image-20220121145723489.png)]

TS is a superset of JS

7.7 TS data type number

Number type is often used in our development. TypeScript, like JavaScript, does not distinguish between integer type (int) and floating point type (double), and is unified as number type.

ES6 adds binary and octal representations, and TypeScript also supports binary, octal and hexadecimal representations:

let num: number = 123
num = 333
let num1: number = 100 // decimal system
let num2: number = 0b111 // Binary, starting with 0b
let num3: number = 0o456 // Octal, starting with 0o
let num4: number = 0x123abc // Hexadecimal, starting with 0x

7.8 TS data type boolean

let num: boolean = true

7.9 TS data type string

let message1: string = "hello world"
let message2: string = "ddg"

const name = "ddg"
const age = 18
const height = 1.88

let message3 = `name:${name}  age:${age} height${height}`
console.log(message3);

7.10 TS data type Array

// Determine the fact that although names is an array type, what type of elements are stored in the array?
// In an array, in TS development, the best data type to store is fixed (string)
// It's a bad habit to store different types in an array
// type annotation
const names: Array<string> = []  // The first method is not recommended (conflicting < div > < / div >) in react jsx and vue jsx)

const names2: string[] = [] // recommend

names.push('abc')

7.11 TS data type Object type

const info = {
  name: "Stupid dog",
  age: 21
}
// If there is no type annotation, it will be automatically derived

7.12 null and undefined types

let n1: null = null
let n2: undefined = undefined

7.13 symbol type

New knowledge of jses6. You can define the same name through symbol, because the symbol function returns different values

const t1 = Symbol("title")
const t2 = Symbol("title")
const info = {
  [t1]: "Stupid dog",
  [t2]: "student"
}
export { }

7.14 any type

In some cases, we really can't determine the type of a variable, and it may change. At this time, we can use any type

let message: any = "hello world"
// When the type is set to any, it can be assigned any value

/* 
 When making some type assertions as any
 When you don't want to add specific data types to some JS, using any won't make mistakes. In fact, it's just like native JS
*/
message = 123
message = true

7.15 unknown type

unknown is a special type in TypeScript. It is used to describe variables with uncertain types.

function foo() {
  return "abc"
}
function bar() {
  return 123
}
let flag = true
let result: any
// let result: unknown
// Unknown types can only be assigned to any and unknown types
// Any type can be assigned to any type

if (flag) {
  result = foo()
} else {
  result = bar()
}

//  If the result is set to any type, there is no problem with this assignment
let message: string = result
let num: number = result
console.log(result);
console.log(message);

// If result is set to unknown type, then assigning values to message and num will not work

export { }

7.16 void type

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

  • We can assign null and undefined to void type, that is, the function can return null or undefined
function sum(num1: number, num2: number) {
  console.log(num1 + num2);
  // If there is no return value, an undefined value will be returned by default
  // In fact, the default return value of this function is void 
  // We can assign null and undefined to void type, that is, the function can return null or undefined
}

// sum(123, 456)
console.log(sum(123, 456));

export { }

7.17 never type

If a function is an endless loop or throws an exception, the function will not have a return value. Then it is not appropriate to write void type or other types as the return value type, so we can use never type

function foo(): never {
  // Dead cycle
  while (true) {
    // Never means that this function will never have a return value
  }
}
function bar(): never {
  throw new Error('Return error')
}

// The message here is a union type, which can be a string or a number
// Prevent others from adding the type annotation of message without writing the corresponding case
function handleMessage(message: string | number | boolean) {
  switch (typeof message) {
    case 'string':
      console.log('string Treatment method');
      break
    case 'number':
      console.log('number Treatment method');
      break
    case 'boolean':
      console.log('boolean Treatment method');
      break
    default:
      // You can never come here, so you can assign it a value
      const check: never = message
  }
}
handleMessage(true)
// What if you want to pass a Boolean value to the handleMessage function?
// You can add a Boolean type in the type annotation of message
// But in this way, you need to add another case 'boolean'

7.18 tuple type

  • First, it is generally recommended to store elements of the same type in the array, and elements of different types are not recommended to be placed in the array. (can be placed in objects or tuples)
  • Secondly, each element in the tuple has its own characteristic type, and the corresponding type can be determined according to the value obtained from the index value;

Basic use

// Tuple tuple, multiple element combination
// Tuple type, which can determine the type of each item in the array,
// If you directly write an any type to the array, it is not safe
// ddg 19 180
const info: [string, number, number] = ["ddg", 18, 180]
const name = info[0]
console.log(name.length);
const age = info[1]
// console.log(age.length);

export { }

Application scenario

// hooks : useState
// const [counter,setCounter] = useState(10)
// If there is an array in useState, it is too unsafe

function useState(state: any) {
  // state can be an array, string, number, Boolean, and so on
  let currentState = state
  const changeState = (newState: any) => {
    currentState = newState
  }

  // After that, we call this function outside and deconstruct. Both values are of type any
  // const arr: any[] = [currentState, changeState]
  const arrTuple: [any, (newState: any) => void] = [currentState, changeState]

  // return arr
  return arrTuple
}
// At this time, counter is still of any type, while setCounter is a function type
const [counter, setCounter] = useState(10)

export { }

Application scenario optimization

// hooks : useState
// const [counter,setCounter] = useState(10)
// If there is an array in useState, it is too unsafe

// If you want to optimize, you need to use generics
function useState<T>(state: T) {
  // state can be an array, string, number, Boolean, and so on
  let currentState = state
  const changeState = (newState: T) => {
    currentState = newState
  }

  // After that, we call this function outside and deconstruct. Both values are of type any
  // const arr: any[] = [currentState, changeState]
  const arrTuple: [T, (newState: T) => void] = [currentState, changeState]

  // return arr
  return arrTuple
}
// It'll be all right at this time
const [counter, setCounter] = useState(10)
const [flag, setFlag] = useState(true)
export { }

7.19 parameter types of functions

7.19.1 function parameters and return values
// Add type annotation to parameters
// Add type annotation to the return value. When there is no return value, it is viod. Add type annotation to the return value, which is usually written after the parameter brackets of the function
// In development, generally, the type of return value can not be written (automatic derivation)
function sum(num1: number, num2: number): number {
  // The above two parameters must be passed. If you pass one, an error will be reported
  return num1 + num2
}
  • Like the type annotation of variables, we usually do not need the return type annotation, because TypeScript infers the return type of the function according to the return value; Some third-party libraries are easy to understand and will explicitly specify the return type, but this depends on personal preferences
7.19.2 parameter types of anonymous functions
function foo(message: string) {
  // Usually, when defining a function, type annotations are added to the parameters
}

const names = ["abc", "c", "a"]
names.forEach((item) => {
  // You can not type item
  // The type of item is derived from the context
  // When we pass one of our functions as a parameter to another function, in some cases, it will automatically deduce the type of the parameter. At this time, we can not add the type annotation
})
7.19.3 function parameters are object types
// A parameter is an object
function printPoint(point: { x: number, y: number }) {
  // Point: {X: number, Y: number} each key in this object can be separated by commas or semicolons
  console.log(point.x);
  console.log(point.y);
}
printPoint({ x: 20, y: 30 })

// Parameter is a string
function printString(message: string) { }
7.19.4 optional parameters of function
// A parameter is an object
// If the user needs to transmit x,y,z, Z, is optional, z?:number, just add a question mark after Z
function printPoint(point: { x: number, y: number, z?: number }) {
  // Point: {X: number, Y: number} each key in this object can be separated by commas or semicolons
  console.log(point.x);
  console.log(point.y);
}
printPoint({ x: 20, y: 30 })
printPoint({ x: 20, y: 30, z: 1111 })

// Parameter is a string
function printString(message: string) { }
export { }
7.19.5 joint type

TypeScript's type system allows us to use multiple operators to build new types from existing types.

  • Union Type
  • A union type is a type that consists of two or more other types
  • The representation can be any of these types
  • Each type in a union type is called a union's members
// number | string union type
function printID(id: number | string) {
  // Be especially careful when using union type values
  // narrow: zoom out
  if (typeof id === 'string') {
    // ts helps determine that the id must be of type string
    console.log(id.toUpperCase());
  } else {
    console.log(id);
  }
}
printID(123)
printID('abc')
export { }
7.19.6 type alias
// Type defines the type alias
type IDType = string | number | boolean
type PointType = {
  x: number,
  y: number,
  z: number
}
function printId(id: IDType) {
}
function Point(id: PointType) {
}
export { }

7.20 type assertion as

Sometimes TypeScript cannot obtain specific type information, so we need to use Type Assertions

For example, we use document Getelementbyid, TypeScript only knows that this function will return HTMLElement, but does not know it

Specific types

TypeScript only allows type assertions to be converted to more specific or less specific type versions. This rule prevents impossible casts

Not very specific. It means any or unknown

// <img id="ddg"/>
const el = document.getElementById("ddg") as HTMLImageElement
el.src = "url address"  // An error will be reported: the attribute "src" does not exist on the type "HTMLElement".
// document.getElementById("ddg") as HTMLImageElement so that no error will be reported when modifying
// Convert a universal type into a specific type

class Person { }

class Student extends Person {
  studying() { }
}

function sayHello(p: Person) {
  // p.studying() / / you can't access it directly 
  (p as Student).studying()
}

const stu = new Student()
sayHello(stu)

// 3. This is not recommended
const message = "hello world"
// const num: number = message
// const num: number = (message as any) as number
// const num: number = (message as unknown) as number
export { }

7.21 non null type assertion

// message ? => undefined | string
function printMessage(message?: string) {
  // Others may or may not pass it on
  // If it is not transmitted, an error will be reported
  // console.log(message.length);

  // However, we can use non null type assertions when we are sure that the passed in parameters have values
  // Non null assertions use, Indicates that it can be determined that an identifier has a value and skip ts's detection of it at the compilation stage
  // !  It means that message must have a value
  console.log(message!.length);
}
printMessage("hello world")
// printMessage()

Although it evades the inspection, the code is not rigorous enough

7.22 use of optional chains es11(es2020)

In fact, the optional chain is not a unique feature of TypeScript. It is an added feature in ES11 (ES2020)

  • Optional chains use the optional chain operator
  • Its function is that when the attribute of the object does not exist, it will be short circuited and return to undefined directly. If it exists, it will continue to execute
type Person = {
  name: string,
  friend?: {
    name: string,
    age?: number,
  }
}

const info: Person = {
  name: "Stupid dog",
  // friend: {
  //   name: "kobe"
  // }
}
// In another file,
console.log(info.name);
//console. log(info.friend);   //  info. Friends may or may not get it. Friend is optional

console.log(info.friend?.name);
// The friend of info may or may not have a value. If there is no friend, the following code will not be executed, and the whole expression returns undefined

7.23 ?? !!

!!

  • Converts a different type to a boolean type
  • Similar to Boolean (variable)

??

  • It is an added feature of ES11
  • Null merge operator (?) Is a logical operator. When the left side of the operator is null or undefined, it returns its right operand; otherwise, it returns the left operand
const message = "hello wolrd"
// const flag = Boolean(message)
// console.log(flag);
// !!  It is the feature of js itself
const flag = !!message
console.log(flag);

let message: string | null = null
// If message is null, give him a default value
const content = message ?? "How do you do"
console.log(content);

export { }

7.24 literal type

Literal quantity is more common than union type,

// If it is a let definition, its type is string
let message = "hello world"
// If const is defined, its type is const message2: "hello world"
// In other words, hello world is a type called literal type
const message2 = "hello world"

let num: 123 = 123
// num = 321 it is impossible to modify the value of literal class. The type must be equal to the value


// The meaning of literal type is that it must be combined with union type
let align: 'left' | 'right' | 'center' = 'left'

align = "right" // This assignment is no problem. The assigned value must be one of the types

export { }

7.25 literal reasoning

// If you don't write a type annotation, he will deduce it automatically
const info = {
  name: "ddg",
  age: 20
}

info.name = "kobe"

// example
type Method = 'GET' | 'POST'
function request(url: string, method: Method) {

}

// Scheme 1: write dead type annotation Proposal 1
// type Request = {
//   url: string,
//   method: Method
// }

// const options: Request = {
//   url: "http://www.daidaigou.top",
//   method: "POST"
// }


// Option 3 
const options = {
  url: "http://www.daidaigou.top",
  method: "POST"
} as const

// When passing, the second parameter will report an error because options The type of Method attribute will be automatically deduced as string, and the second parameter of the function is Method
// request(options.url, options.method)

// request(options.url, options.method)

// Scheme 2 uses type assertion
request(options.url, options.method as Method)

7.26 type reduction

  • Type Narrowing in English is Type Narrowing
  • We can change the execution path of TypeScript through a judgment statement similar to typeof padding = = = "number"
  • In a given execution path, we can reduce types smaller than those declared. This process is called reduction
  • The typeof padding === "number" we wrote can be called type guards

Common types of protection are as follows

  • typeof
  • Equal reduction (e.g. = =,! = =)
  • instanceof
  • in
  • Wait
// 1. Type reduction of typeof
function printID(id: number | string) {
  // id is a union type and cannot be processed casually
  // The whole process of the statement is called type reduction
  if (typeof id === 'string') {
    // The id obtained here must be a string type
    console.log(id.toUpperCase());
  } else {
    console.log(id);

  }
}

// 2. Reduction of the type of equality (= = =! = =! = switch)

function printDireaction(direction: 'left' | 'right' | 'top' | 'bottom') {
  // if (direction === "left") {

  // }else if () {

  // }

  // switch(direction){
  //   case 'left': wait
  // }
}

// 3.instanceof 
function printTime(time: string | Date) {
  if (time instanceof Date) {
    // If it is date type
  } else {
    console.log('xxx');
  }
}

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)
// work passes an instance of Student or Teacher

// 4. in
type Fish = {
  swimming: () => void
}

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

function walk(animal: Fish | Dog) {
  if ('swimming' in animal) {
    // Is to judge the attribute. The Fish Dog here is not a class, but a literal quantity
    animal.swimming()
  } else {
    animal.running()
  }
}

const fish: Fish = {
  swimming() {
    console.log("swimming");

  }
}
walk(fish)

7.27 function type

7.27.1 function type
// 1. How to write types in parameters when functions are used as parameters
function foo() { }
function bar(fn: () => void) {
  fn()
}

bar(foo)

// 2. When defining constants, write the type of function
const add: (num1: number, num2: number) => number = (num1: number, num2: number) => {
  return num1 + num2
}
7.27.2 optional types of parameters
// y -> undefined | number
function foo(x: number, y?: number) {

}
// The first parameter must be selected!

foo(20, 30)
foo(40)
7.27.3 default values of parameters
// Write the required parameters first - parameters with default values - optional parameters
function foo(x: number = 20, y: number = 100) {
  console.log(x, y);

}
foo(undefined, 40)
7.27.4 residual parameters of function
function sum(...nums: number[]) {
  console.log(nums);

}
sum(10, 20, 30, 40, 50)
7.27.5 this
// this can be derived, info object (derived from TS)
const info = {
  name: "Stupid dog",
  eating() {
    console.log(this.name + "  eating");

  }
}
info.eating()
// this cannot be used indiscriminately in TS
// The independent function can't deduce this
// Solution: pass a parameter and put it first
function eating(this: { name: string }) {
  console.log(this.name + "  eating");

}
const info = {
  name: "Stupid dog",
  eating: eating,

}
// Implicit binding
info.eating()


// Display binding
// If this is passed, eating() cannot be written directly
eating.call({ name: "2222" })

export { }
7.27.6 overloading of functions

In TypeScript, if we write an add function to add string and number types, how should we write it?

  • In TypeScript, we can write different overload signatures to indicate that functions can be called in different ways
  • It is generally to write two or more overloaded signatures, and then write a general function and implementation
// Function overloading: several functions with the same function name but different parameters are function overloading
// TS function overloading, top-down matching, and the function body is written at the end

// Written in other languages
// function add(num1: number, num2: number) { }
// function add(num1: number, num2: number, num3: number) { }

// TS function overload writing method
function add(num1: number, num2: number): number; // No function body
function add(num1: string, num2: string,): string;

// Implementation function, this function is the implementation function
function add(num1: any, num2: any): any {
  // Function body
  if (typeof num1 === 'string' && typeof num2 === 'string') {
    return num1.length + num2.length
  }
  return num1 + num2
}

console.log(add(20, 30));
console.log(add('123', '456'));

// In function overloading, the implementation function cannot be called directly. It must be matched from top to bottom
// add({name: "stupid dog"}, {age:29})

// If you can simply implement it through union types, use union types

// Implementation method 1: joint type implementation
// function getLength(args: string | any[]) {
//   return args.length
// }

// console.log(getLength("abc"));
// console.log(getLength([12, 23, 11, 23]));

// Implementation mode 2: function overload implementation
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([12, 23, 11, 23]));

Category 7.28

  • In the early JavaScript development (ES5), we need to realize class and inheritance through function and prototype chain. Starting from ES6, the class keyword is introduced to make it easier to define and use classes
  • As a superset of JavaScript, TypeScript also supports the use of class keyword, and can also carry out static type detection on class properties and methods
  • In fact, during the development of JavaScript, we are more used to functional programming
    • For example, in the development of React, more function components are used and the development mode combined with Hook
    • For example, in the development of Vue3, the use of Composition API is also more advocated
  • However, when encapsulating some businesses, classes have more powerful encapsulation, so we also need to master them
  • For class definition, we usually use the class keyword:
    • In the object-oriented world, everything can be described by class structure;
    • Class contains unique attributes and methods;
7.28.1 definition of class
// The properties of a class must be initialized, either directly at the time of definition or with a constructor
class Person {
  // Properties and methods
  // You can directly assign and initialize after defining the attribute
  // name: string = ""
  // age: number = 0
  name: string
  age: number

  // constructor can also be used for initialization
  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }

  eating() {
    console.log(this.name + "  eating");

  }
}
const p = new Person("ddg", 21)
export { }
7.28.2 inheritance of classes
class Person {
  name: string = ""
  age: number = 0
  eating() {
    console.log("eating");
  }
}
class Student extends Person {
  sno: number = 0
  studying() {
    console.log("studying");
  }
}
class Teacher extends Person {
  titlle: string = ""
  teaching() {
    console.log("Teachering");
  }
}

const stu = new Student()
console.log(stu);
stu.eating()

class Person {
  name: string
  age: number
  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }
  eating() {
    console.log("Person eating");
  }
}
class Student extends Person {
  sno: number
  constructor(name: string, age: number, sno: number) {
    super(name, age)  // Call the constructor of the parent class
    this.sno = sno
  }
  // If the subclass is not satisfied with the method of the parent class, it can override it
  eating() {
    console.log("Student eating");
    // What if you have to call the method of the parent class in the subclass?
    super.eating()
  }
  studying() {
    console.log("studying");
  }
}


const stu = new Student("ddg", 21, 201813212)
console.log(stu);
stu.eating()

export { }
7.28.3 member modifier of class

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

  • Public modifies attributes or methods that are visible and public anywhere. The default attribute is public;
  • Private modifies attributes or methods that are only visible and private in the same class and the current class;
  • Protected modifies attributes or methods that are visible and protected only in the class itself and its subclasses;
// protected: it can be accessed inside the class and in subclasses,
class Person {

  protected name: string = ""
  getName() {
    return this.name
  }
}
const p = new Person()
console.log(p.name); // This is not accessible, and an error will be reported

export { }
7.28.4 readonly read only attribute
class Person {
  // Read only attribute, which can be assigned in the constructor. After assignment, it cannot be modified
  // The property itself cannot be modified, but if it is an object type, the properties in the object can be modified. Similar to const 
  readonly name: string
  age?: number
  readonly friend?: Person
  constructor(name: string, friend?: Person) {
    this.name = name
    this.friend = friend
  }
}

const p = new Person("ddg", new Person("boke"))

// At this time, the name can only be accessed and cannot be modified
// p.name = "123"
console.log(p.name);
console.log(p.friend);

// Friends cannot be modified directly
// p.friend = new Person("hames")
if (p.friend) {
  p.friend.age = 30
}
7.28.5 getter and setter
class Person {
  private _name: string
  constructor(name: string) {
    this._name = name
  }
  // Accessor setter / getter
  // Suggestion: private attribute, beginning with underscore
  set name(newName) {
    this._name = newName
  }
  get name() {
    return this._name
  }

}

const p = new Person("Stupid dog")
// console.log(p.name);

p.name = "Stupid dog------"
console.log(p.name);
7.28.6 static members
class Student {
  static time: string = "20:00"
  static attdendClass() {
    console.log('Go to school');
  }

}
// It can be accessed directly through classes
console.log(Student.time);
console.log(Student.attdendClass());

export { }
7.28.7 abstract classes
  • Abstract functions can have no function body. Abstract functions must be in abstract classes
  • Abstract classes cannot be instantiated, that is, they cannot be created through new
  • Methods of abstract classes must be implemented in subclasses
function makeArea(shape: Shape) {
  return shape.getArea()
}

// Parent class
abstract class Shape {
  // Abstract functions can have no function body. Abstract functions must be in abstract classes
  // Abstract classes cannot be instantiated
  // Methods of abstract classes must be implemented in subclasses
  abstract getArea(): number
}

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

  constructor(width: number, height: number) {
    // This is a subclass. You must call super() of the parent class
    super()
    this.width = width
    this.height = height
  }

  getArea() {
    return this.width * this.height
  }
}

class Circle extends Shape {
  private r: number

  constructor(r: number) {
    super()
    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))
// makeArea(new Shape())

// makeArea(123)
// makeArea("123")
7.28.8 type of class
class Person {
  name: string = "123"
  eating() { }
}
const p = new Person()

// Class itself can also be used as a type
const p1: Person = {
  name: "Stupid dog",
  eating() { }
}

function printPerson(p: Person) {
  console.log(p.name);
}
printPerson(new Person())
printPerson({ name: "hit", eating: function () { } })

7.29 interface

7.29.1 interface definition object type
// The first is to declare an object type through a type alias
// type InfoType = { name:string,age:number}

// The second is through the interface
// interface type name
// The type name after the interface is usually preceded by an uppercase I 
interface InfoType {
  readonly name: string,
  age: number
}

const info: InfoType = {
  name: "ddg",
  age: 12
}

// Because the read-only attribute is added, an error will be reported
// info.name = "@22"
7.29.2 index type
// interface to define the index type
interface IndexLanguage {
  //  index is a formal parameter
  // [index: number]: string | boolean
  [index: number]: string
}

const frontLanguage: IndexLanguage = {
  0: "html",
  1: "css",
  2: "js",
  3: "vuejs",
  // 4: true
}

interface ILanguageYear {
  // name is a parameter
  [name: string]: number
}

const languageYear = {
  "c": 1972,
  "java": 1995,
  "js": 1996,
  "ts": 2014
}
7.29.3 function type
interface CalcFn {
  // Interface definition function type
  (n1: number, n2: number): number
}

// It is recommended to use type to define function type
// type 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)
7.29.4 interface inheritance

There are two ways to combine multiple interfaces

  1. Interface inheritance
  2. Cross type
interface ISwim {
  swmming: () => void
}
interface IFly {
  flying: () => void
}

interface IAaction extends ISwim, IFly {
  // Interface inheritance, supporting multiple inheritance
}

const action: IAaction = {
  swmming() { },
  flying() { }
}
7.29.5 crossing type
// A way to combine types: Union type
type DdgType = number | string
type Direaction = "left" | "right" | "center"

// Another way to combine types: cross type
// The & here means that it conforms to both the previous type and the following type
type oneType = number & string

// &: what does it mean

interface ISwim {
  swmming: () => void
}
interface IFly {
  flying: () => void
}

type mytype1 = ISwim | IFly
type mytype2 = ISwim & IFly

const obj: mytype1 = {
  // You can choose between swmming and flying
  swmming() {}
}
const obj2: mytype2 = {
  // You can write both
  swmming() {},
  flying() { }
}
export { }
7.29.6 implementation of interface
interface IEat {
  eating: () => void
}
interface ISwim {
  swmming: () => void
}

// Class implementation interface
class Animal {

}
// Class inheritance: only single inheritance can be implemented 
// Implementation: implement interfaces, and multiple interfaces can be implemented
class Fish extends Animal implements ISwim, IEat {
  eating() {
    console.log('fish eating');
  }
  swmming() {
    console.log('fish swmming');
  }
}
class Person implements ISwim {
  swmming() {
    console.log('person swimming');

  }
}
// Write some common APIs: interface oriented programming
function swimAction(swimable: ISwim) {
  swimable.swmming()
}

// 1. All objects corresponding to classes that implement interfaces can be passed in
swimAction(new Fish())
swimAction(new Person())
7.29.7 difference between interface and type
  • We will find that both interface and type can be used to define object types. Which one should we choose when defining object types in development?
    • If you are defining non object types (functions, union types), it is generally recommended to use types, such as Direction, Alignment, and some functions;
  • If you define object types, they are different
    • Interface can repeatedly define attributes and methods for an interface;
    • type defines an alias, which cannot be repeated;

[the external chain picture transfer fails, and the source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-fir6veya-1643279385256) (codewhy-vue3-componentization. assets/image-20220127120910909.png)]

interface IFoo {
  name: string
}
interface IFoo {
  age: number
}
// TS allows you to define two interfaces with the same name. TS will merge these two interfaces internally

const foo: IFoo = {
  age: 18,
  name: "sting"
}


// type does not allow two aliases with the same name, that is, aliases cannot be repeated
// type IBar = {
//   name: string
// }
// type IBar = {
//   age: number
// }
7.29.8 literal assignment
interface IPerson {
  name: string,
  age: number,
  height: number
}

const info = {
  name: "ddg",
  age: 19,
  height: 2.0,
  address: "Beijing"
}
// During type checking, info is assigned to IPerson, and the two are compared. First erase the address, and then compare how they are the same. If they are different, assignment is allowed
// freshness erase
const p: IPerson = info

// Its meaning
function p2(obj: IPerson) { }
// P2 ({Name: "DDH", age: 20, height: 1.8, address: "Beijing"}) / / an error will be reported because an additional address attribute is passed
const obj2 = { name: "ddh", age: 20, height: 1.8, address: "Beijing" }
p2(obj2)
7.29.9 enumeration types
  • Enumeration is actually to enumerate a group of possible values one by one and define them in a type. This type is the enumeration type
  • Enumeration allows developers to define a set of named constants, which can be numeric or string types
// type Direction = "left" | "Right" | "Top" | "Bottom"

enum Direction {
  LEFT,
  RIGHT,
  TOP,
  BOTTOM
}


function turnDirection(direction: Direction) {
  switch (direction) {
    case Direction.LEFT:
      console.log("Change the direction of the character 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 down")
      break;
    default:
      // Only by exhausting the above types, there will be no error reported here
      const foo: never = direction;
      break;
  }
}

turnDirection(Direction.LEFT)
turnDirection(Direction.RIGHT)
turnDirection(Direction.TOP)
turnDirection(Direction.BOTTOM)
enum Direction {
  // The default value of these four properties is 0, and you can also modify the value
  // If only the first one is modified and the first one is changed to 100, the next three will increase
  // If only the fourth one is modified, the first one is 0, the second one is 1, and the third one is 2
  // Its value can also be a string, usually a string or a number
  LEFT = 100,
  RIGHT = 200,
  TOP = 300,
  BOTTOM = 400
}


function turnDirection(direction: Direction) {
  // console.log(direction);  Enumeration types actually have values

  switch (direction) {
    case Direction.LEFT:
      console.log("Change the direction of the character 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 down")
      break;
    default:
      // Only by exhausting the above types, there will be no error reported here
      const foo: never = direction;
      break;
  }
}

turnDirection(Direction.LEFT)
turnDirection(Direction.RIGHT)
turnDirection(Direction.TOP)
turnDirection(Direction.BOTTOM)

export { }

7.30 generics

  • The main purpose of software engineering is to build not only clear and consistent API s, but also make your code highly reusable
    • For example, we can encapsulate some API s through functions, and let functions help us complete different operations by passing in different function parameters
    • But can the type of parameter be parameterized
  • What is type parameterization?
    • Let's put forward a requirement: encapsulate a function, pass in a parameter, and return this parameter;
  • If we are thinking in TypeScript, we should consider that the type of this parameter and the return value should be consistent:
7.30.1 basic use
// Parameterization of types

// When defining this function, I do not determine the type of these parameters
// Instead, let the caller tell me in the form of parameters what type the function parameters here should be
function sum<Type>(num: Type): Type {
  return num
}

// 1. Call method 1: clear incoming type
sum<number>(20)
sum<{ name: string }>({ name: "why" })
sum<any[]>(["abc"])

// 2. Call method 2: push type to
sum(50)
sum("abc")
7.30.2 basic supplement of generics
  • T: Abbreviation for Type

  • K. V: abbreviation of key and value, key value pair

  • E: Abbreviation for Element

  • O: Abbreviation for Object

function foo<T, E>(arg1: T, arg2: E) { }
foo<number, string>(10, 'How do you do~~~')
7.30.3 generic interfaces
interface IPerson<T1 = string, T2 = number> {
  name: T1,
  age: T2
}

// The corresponding type must be written here and will not be deduced automatically
const p: IPerson<string, number> = {
  name: "ddg",
  age: 20
}

const p2: IPerson = {
  name: "ddg1",
  age: 30
}
7.30.4 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 names1: string[] = ["abc", "cba", "nba"]
const names2: Array<string> = ["abc", "cba", "nba"] // Not recommended (react JSX < >)
export { }
7.30.5 type constraints for generics

For example, both string and array have length, or some objects also have length attribute

So as long as the attribute with length can be used as our parameter type, how should we operate?

interface ILength {
  length: number
  // Indicates: if it is an object type, it must have the length attribute
}

// extends inherits a type,
// Make a constraint on this generic type
function getLength<T extends ILength>(arg: T) {
  return arg.length // You must have the attribute length, so that you will not report an error after passing it
}

// Getlength (123) / / type number has no length attribute
getLength("abc") // Because the string itself has the length attribute
getLength(["abc", "cba"])
getLength({ length: 100 })
console.log(getLength({ length: 100 }));
console.log(getLength(["abc", "cba"]));

7.31 modular development

TypeScript supports two ways to control our scope

  • Modularization: each file can be an independent module, which supports ES Module and CommonJS
  • Namespace: declare a namespace through namespace

Namespace namespace

In the early days of TypeScript, namespaces were called internal modules. The main purpose is to divide the scope within a module to prevent some naming conflicts

export namespace time {
  // In addition to the time curly braces, if you want to get it, you must export it
  export function format(time: string) {
    return "2022-22-02"
  }
  export function foo() { }
  export let name: string = "Stupid dog"
}

export namespace price {
  export function format(price: number) {
    return "99.9999"
  }
}

time.format
// time.foo
// main.ts
import { time, price } from './utils/format';
console.log(time.format('xxx'));

7.32 type search

In the past, almost all types in our typescript were written by ourselves, but we can also use some other types:

const imgId = document.getElementById('image') as HTMLImageElement

Will you wonder where our HTMLImageElement type comes from? Why can a document even have a getElementById method?

In fact, this involves typescript's type management and search rules

  • The typescript files we wrote before are ts files, which will eventually be output js file is also where we usually write code
  • There is another kind of file d.ts file, which is used for type declaration. It is only used for type detection to tell typescript what types we have

So where does typescript find our type declaration?

  • Built in type declaration
  • Externally defined type declaration (usually the type declaration file of the third-party library, such as axios)
  • Define your own type declaration

7.33 built in type declaration

  • The built-in type declaration is a declaration file that comes with typescript and helps us build some standardized API s of JavaScript runtime;
  • Including built-in types such as Math and Date, as well as DOM API s such as Window and Document

Built in type declarations are usually included in the environment where we install typescript Official website address

7.34 external definition type declaration

For example, axios is an externally defined type declaration

node_ modules => axios =>index. d.ts . Axios has helped us

  • External type declarations are usually required when we use some libraries (such as third-party libraries).
  • These libraries usually have two types of declarations:
    • Method 1: make type declaration in your own library (write. d.ts file), such as axios
    • Method 2: store the type declaration file through a public library of the community, DefinitelyTyped
      • GitHub address of the Library: https://github.com/DefinitelyTyped/DefinitelyTyped/
      • The library looks for the address where the installation method is declared: https://www.typescriptlang.org/dt/search?search=
      • For example: npm i react, NPM I @ types / react -- save dev

7.35 self defined type declaration

Generally, a new one is created under src d. File at the end of TS

// declare is declared
declare module 'lodash' {
  export function join(arr: any[]): void { }
}
// main.ts, provided that NPM I @ types / lodash -- save dev has not been executed
import lodash from 'lodash'
console.log(lodash.join(["1"]));

Declare variable

In the root file index.html In the file
  <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js
  "></script>
  <script>
    let whyName = "coderwhy"
    let whyAge = 18
    let whyHeight = 1.88

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

    function Person(name, age) {
      this.name = name
      this.age = age
    }
  </script>
// main.ts
import { add, sub } from './utils/math';

import { time, price } from './utils/format';

// import lodash from 'lodash'
// console.log(lodash.join(["1"]));


// In TS, the introduction of a picture will also report an error
import nhltImg from './img/nhlt.jpg'

console.log(add(20, 30));
console.log(sub(20, 30));

console.log(time.format('xxx'));

console.log(whyName);
console.log(whyAge);
console.log(whyHeight);
console.log(whyFoo());

const p = new Person("ddg", 20)
console.log(p);

$.ajax({})
// ddg.d.ts
// The. d.ts file does not need to be written and implemented, but only defined
// declare is declared
// This is the declared module
declare module 'lodash' {
  export function join(arr: any[]): void { }
}

// You can also 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)
}

// Declaration document
declare module '*.jpg'
declare module '*.jpeg'
declare module '*.png'
declare module '*.svg'
declare module '*.gif'

// Declaring Namespace 
// For example, in index The cdn address of jq is introduced into HTML
declare namespace $ {
  export function ajax(settings: any): any
}

Keywords: Javascript Front-end TypeScript

Added by menelaus8888 on Thu, 27 Jan 2022 14:14:45 +0200