TypeScript from introduction to practice [geek time] update

Website recommendation

ts-playground

ts Chinese Manual

Introduction to ts

Type basis

Strong type and weak type

  • Strongly typed language: it is not allowed to change the data type of a variable unless it is cast
  • Weakly typed language: variables can be assigned different data types

Static type and dynamic type

  • Statically typed language: determines the type of all variables at compile time
  • Dynamically typed language: determines the type of all variables at the execution stage

initialization

npm i typescript -g
# initialization
npm init -y
tsc --init
{
    "clean-webpack-plugin": "^3.0.0",
    "html-webpack-plugin": "^3.2.0",
    "ts-loader": "^8.1.0",
    "typescript": "^4.2.4",
    "webpack": "^4.32.2",
    "webpack-cli": "^3.3.2",
    "webpack-dev-server": "^3.5.1",
    "webpack-merge": "^4.2.1"
}

Environment configuration webpack base. config. js

npm i webpack webpack-cli webpack-dev-server -D
npm i ts-loader typescript -D
npm i html-webpack-plugin -D
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  entry: {
    app: './src/index.ts',
  },
  output: {
    filename: 'app.js',
  },
  resolve: {
    extensions: ['.js', '.tsx', '.ts'],
  },
  module: {
    rules: [
      {
        test: /\.tsx?$/i,
        use: [
          {
            loader: 'ts-loader',
          },
        ],
        exclude: /node_modules/,
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/tpl/index.html',
    }),
  ],
}

Environment configuration webpack dev.config. js

  • Soap ignores the chain information of the source map
  • module locate ts source code
  • Eval source map packages the source map into a file as a url
module.exports = {
  //
  devtool: 'cheap-module-eval-source-map',
}

Environment configuration webpack pro. config. js

npm i clean-webpack-plugin -D
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

module.exports = {
  plugins: [new CleanWebpackPlugin()],
}

Environment configuration webpack config. js

npm i webpack-merge -D # Merge two webpack configuration items
const merge = require('webpack-merge')
const baseConfig = require('./webpack.base.config')
const devConfig = require('./webpack.dev.config')
const proConfig = require('./webpack.pro.config')

let config = process.NODE_ENV === 'development' ? devConfig : proConfig

module.exports = merge(baseConfig, config)

hello world

let hello: string = 'hello world'
document.querySelectorAll('.app')[0].innerHTML = hello

Basic type

ES6 data type

  • Boolean
  • Number
  • String
  • Array
  • Function
  • Object
  • Symbol
  • undefined
  • null

TypeScript data type

Added on the basis of ES6 data type

  • void
  • any
  • never
  • tuple
  • enumeration
  • Advanced type

type annotation

  • Equivalent to a type declaration in a strongly typed language
  • Syntax: (variable / function): type
// Original type
let bool: boolean = true
let num: number = 123
let str: string = 'abc'

// array
let arr1: number[] = [1, 2, 3]
let arr2: Array<number | string> = [1, 2, 3, '4']

// tuple
let tuple: [number, string] = [0, '1']

// function
let add = (x: number, y: number): number => x + y
let compute: (x: number, y: number) => number
compute = (a, b) => a + b

// object
let obj: { x: number; y: number } = { x: 1, y: 2 }

// symbol
let s1: symbol = Symbol()

// void
let noReturn = () => {}

// any can modify it at will
let x
x = 1
x = []

undefined and null

  • Is a subtype of all types, that is, you can assign undefined and null to variables of type number
let un: undefined = undefined
let nu: null = null
/*
terms of settlement
  1.tsconfig Modify "strictnullchecks" in: false
  2.Use union type let num: number | undefined | null = 123
*/
num = undefined // report errors

never

  1. A function throws an exception
  2. A function never returns a result
// never
let error = () => {
  throw new Error('error')
}
let endless = () => {
  while (true) {}
}

Enumeration type

Enumeration: a set of constants with names (which can be understood as address book)

  • Enum is defined using enum keyword
// Numeric enumeration (reverse mapping)
enum Role {
  Reporter = 1,
  Developer,
  Maintainer,
  Owner,
  Guest,
}

// String Enum 
enum Message {
  Success = 'success',
  Fail = 'fail',
}

// Heterogeneous enumeration
enum Answer {
  N,
  Y = 'Yes',
}

// Constant enumeration (which will be removed at compile time) works: you don't need an object, you need the value of an object
const enum Month {
  Jan,
  Feb,
  Mar,
}
let month = [Month.Jan, Month.Feb, Month.Mar]

Enumerating members

  1. Constant enumeration

    • Without initial value
    • Reference to an existing enumeration member
    • Constant expression
  2. Compute enumeration

    The calculation is not performed during the compilation phase, but remains until the execution phase of the program

// Enumerating members
enum Char {
  // constant members
  a,
  b = Char.a,
  c = 1 + 3,
  // computed member
  d = Math.random(),
  e = '123'.length,
}

Enumeration type

// Enumeration type (in some cases, enumeration and enumeration members can exist as a single type)
enum E {
  a,
  b,
} // Enumeration members do not have any initial values
enum F {
  a = 0,
  b = 1,
} // All members are numeric enumerations
enum G {
  a = 'apple',
  b = 'banana',
}

// Comparisons cannot be made between different enumeration types
let e: E = 3
let f: F = 3

let e1: E.a = 1
let e2: E.b
let e3: E.a = 1

let g1: G = G.a
let g2: G.a

Interface

Object type interface

One of the core principles of ts is to type check the structure of values, which is sometimes called "duck type identification method". In ts, the function of interfaces is to name these types and define contracts with your code or third-party code

  • If the incoming interface meets the necessary conditions, it is allowed. Even if the incoming redundant fields can pass the type check
  • Exception: if an object literal is passed in directly, the ts will check for additional fields
    1. Pass the object literal to a variable
    2. Use type assertion as result < result >
    3. Use string index signature [x: string]: any

The variable uses const and the attribute uses readonly

interface List {
  readonly id: number // read-only
  name: string
  [x: string]: any
  age?: number // ? not essential
}

interface Result {
  data: List[]
}

function render(result: Result) {
  result.data.forEach(value => {
    console.log(value.id, value.name)
    if (value.age) {
      console.log(value.age)
    }
  })
}

let result = {
  data: [
    { id: 1, name: 'A', sex: 'male' },
    { id: 2, name: 'B' },
  ],
}

render((<Result>{
  data: [
    { id: 1, name: 'A', sex: 'male' },
    { id: 2, name: 'B' },
  ],
}) as Result)

You can use indexable types when you are not sure how many properties there are in an interface

  • String and numeric index
  • Two types of indexes can be used at the same time, but the return value of a numeric index must be a subtype of the return value type of a string index (indexing with 100 is equivalent to indexing with "100")
// Digital index
interface StringArray {
  [index: number]: string
}
let chars: StringArray = ['A', 'B']

// String index
interface Names {
  [x: string]: string
  [z: number]: string
}

Function type interface

The following two definitions are equivalent

// Variable declaration
let add: (x: number, y: number) => number

// Interface declaration
interface Add {
  (x: number, y: number): number
}

Type alias

// Use type alias
type Add = (x: number, y: number) => number
let add: Add = (a, b) => a + b

Hybrid interface

interface Lib {
  (): void
  version: string
  doSomething(): void
}

function getLib() {
  let lib: Lib = (() => {}) as Lib
  lib.version = '1.0'
  lib.doSomething = () => {}
  return lib
}

let lib1 = getLib()
lib1()
lib1.doSomething()

Summary of function related knowledge points

Four ways of function definition

  • The latter three are just the definition of function types, but have no specific implementation
function add1(x: number, y: number) {
  return x + y
}
let add2: (x: number, y: number) => number
type add3 = (x: number, y: number) => number
interface add4 {
  (x: number, y: number): number
}
// Optional parameters must precede the required parameters
function add5(x: number, y?: number) {
  return y ? x + y : x
}

// Function overload (two functions have the same name and different number / type of parameters)
function add6(...rest: number[]): number
function add6(...rest: string[]): string
function add6(...rest: any[]): any {
  let first = rest[0]
  if (typeof first === 'string') {
    return rest.join('')
  }
  if (typeof first === 'number') {
    return rest.reduce((pre, cur) => pre + cur)
  }
}
console.log(add6(1, 2, 3)) // 6
console.log(add6('a', 'b', 'c')) // abc

class

Inheritance and member modifiers

  • All properties are public by default
  • The private member private can only be called in the class itself, not by the instance of the class or by the subclass
  • protected is similar to private, but it can be called in subclasses
  • readonly sets the property to read-only
class Dog {
  // If you add private to the constructor: it can neither be instantiated nor inherited
  constructor(name: string) {
    this.name = name
  }
  name: string
  run() {}
  private pri() {}
  protected pro() {}
  readonly legs: number = 4
}

console.log(Dog.prototype)
let dog = new Dog('wang')
console.log(dog)
// dog.pri()
// dog.pro()

class Husky extends Dog {
  constructor(name: string, public color: string) {
    super(name)
    this.color = color
    // this.pri()
    this.pro()
  }
  // color: string
}

Abstract classes and polymorphism

  • Cannot inherit an instance of an abstract class

Benefits of abstract classes:

  1. It can isolate the commonness of some things, which is conducive to code reuse and expansion
  2. Abstract classes can realize polymorphism (define a method in the parent class, have different implementations of this method in multiple subclasses, and perform different operations on different objects during program running, so as to realize runtime binding)
abstract class Animal {
  eat() {
    console.log('eat')
  }
  abstract sleep(): void // Abstract method
}
// let animal = new Animal()

class Dog extends Animal {
  constructor(name: string) {
    super()
    this.name = name
  }
  name: string
  run() {}
  sleep() {
    console.log('dog sleep')
  }
}
let dog = new Dog('wang')
dog.eat()

class Cat extends Animal {
  sleep() {
    console.log('cat sleep')
  }
}
let cat = new Cat()
let animals: Animal[] = [dog, cat]
animals.forEach(i => {
  i.sleep()
})

Polymorphism in inheritance

class WorkFlow {
  step1() {
    return this
  }
  step2() {
    return this
  }
}
new WorkFlow().step1().step2()

// Polymorphism in inheritance: this can be either a parent type or a child type
class MyFlow extends WorkFlow {
  next() {
    return this
  }
}
new MyFlow().next().step1().next().step2()

Relationship between class and interface

be careful:

  1. Class must declare all properties of the interface when it implements the interface
  2. An interface can only constrain public members of a class
  3. An interface cannot constrain the constructor of a class
interface Human {
  // new (name: string): void
  name: string
  eat(): void
}

class Asian implements Human {
  constructor(name: string) {
    this.name = name
  }
  // private name: string
  name: string
  eat() {}
  sleep() {}
}

Differences between implements and extensions

  • implements treats the class as an interface, which means that you must implement all the methods defined in the class, whether they have a default implementation in the class or not, and there is no need to use super()
  • Extensions requires super()
interface Human {
  name: string
  eat(): void
}

interface Man extends Human {
  run(): void
}

interface Child {
  cry(): void
}

interface Boy extends Man, Child {}
let boy: Boy = {
  name: '',
  run() {},
  eat() {},
  cry() {},
}

In addition to inheriting the interface, the interface can also inherit the class, which is equivalent to that the interface abstracts the members of the class (only the member structure of the class without specific implementation)

class Auto {
  state = 1
}
// state is implicit in the interface
interface AutoInterface extends Auto {}
// Subclasses of Auto can also implement the interface of AutoInterface. C is not a subclass of Auto and does not contain non-public members of Auto
class C implements AutoInterface {
  state = 1
}
// It is a subclass of Auto and inherits state. When the interface pulls out the members of the class, it pulls out not only the public members, but also the protected members and private members
class Bus extends Auto implements AutoInterface {}

Relationship:

  1. Interfaces (reuse between interfaces) and classes (reuse between methods and attributes) can inherit from each other
  2. Interfaces can be implemented through classes, but interfaces can only restrict the public members of classes
  3. Interfaces can also pull out members of classes, including public members, private members and protected members

Keywords: Javascript

Added by loureiro on Wed, 02 Mar 2022 02:25:22 +0200