Not much more is said about typescript’s introduction.

Compile the TypeScript

We know that typescript only runs in Node or a browser when we compile javascript. So how do we compile typescript?

  • throughtscCommand.
    • To execute this command next, we need to install typescript globally. This allows you to compile the TS file with this command. It generates a js file with the corresponding name, which can then be run through Node or a browser.
  • throughts-nodeLibrary to run ts files directly in Node.
    • Install the ts – node librarynpm install ts-node -g.
    • And it relies on two other librariestslib.@types/node. So we can we also need to installnpm install tslib @types/node -g
  • Webpack configures the relevant loader to compile ts files.

These libraries need to be installed

    "html-webpack-plugin": "^ 5.3.2." "."ts-loader": "^ 9.2.3." "."typescript": "^ 4.3.5." "."webpack": "^ 5.44.0"."webpack-cli": "^ 4.7.2." "."webpack-dev-server": "^ 3.11.2"
Copy the code

And TSC –init is required to generate the ‘tsconfig.json’ file, otherwise an error will be reported during compilation. Configure the script in the package.json file.

  "scripts": {
    "build": "webpack"."serve": "webpack serve"
  }
Copy the code

Webpack configuration

    const path = require('path')
    const HtmlWebpackPlugin = require('html-webpack-plugin')

    module.exports = {
      mode: "development".entry: "./src/main.ts".output: {
        path: path.resolve(__dirname, "./dist"),
        filename: "bundle.js"
      },
      devServer: {},resolve: {
        extensions: [".ts".".js".".cjs".".json"]},module: {
        rules: [{test: /\.ts$/,
            loader: 'ts-loader'}},plugins: [
        new HtmlWebpackPlugin({
          template: "./index.html"}})]Copy the code

Run NPM Run serve to run the project.

TypeScript type

TypeScript is a super version of JavaScript. Js types exist in TS, and TS extends its own types, so let’s take a look. Note that values of primitive types can be assigned to the corresponding wrapper type, but the wrapper type cannot be assigned to the corresponding primitive type.

    const message1: String = 'HelloWorld'// This is ok
    const message2: string = new String('Hello World') // There will be an error
Copy the code

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

Unknown types can only be assigned to any and unknown types. In some cases, we can use any (similar to the Dynamic type in the Dart language) when we really can’t determine the type of a variable and it may change a bit.

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

unknowntype

Unknown is a special type in TypeScript that describes variables of uncertain type. The unknown type can only be assigned to any and unknown types. The any type can be assigned to any type. So unknown is more secure than any.

    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
    // The received return value may be string or number.
    let result: unknown // It is best not to use any
    if (flag) {
      result = foo()
    } else {
      result = bar()
    }
Copy the code

voidtype

  • 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.
  • Function we didn’t write any type, so it returns void by default, or we can display it to specify that it returns void.
    function sum(num1: number, num2: number) :void {
      console.log(num1 + num2)
      return 'pp' // If the specified function does not return a value, an error is reported. But you can return undefined, null.
    }

    sum(20.30)
Copy the code

nevertype

Never indicates the type of value that never occurs.

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

No, it’s not appropriate to write void or any other type as a return value type, so we can use never.

tupletype

Tuple is a tuple type, which is also found in many languages, such as Python, Swift, and so on.

So what’s the difference between a tuple and an array?

  • First, it is generally recommended to store elements of the same type in arrays, and not to store elements of different types in arrays. (Can be placed in objects or tuples).
  • Second, each element in a tuple has its own unique type, which can be determined by the value obtained from the index value.
  • It’s an array of fixed length and type.
    const info: [string.number.number] = ["zh".20.0]
    const name = info[0]
    console.log(info.slice(0.1))
Copy the code

Now that we have an overview of the tuple, what scenarios will it be used in? Take a look at the following example.

Simply implement a useState hook function. We all know useState hooks, but an array containing two elements. The first element is the value passed in, and the second element is a function, so we can constrain it with a tuple.

    function useState<T> (state: T) {
    
      let currentState = state
      
      const changeState = (newState: T) = > {
        currentState = newState
      }
      // constrain the return value
      const tuple: [T, (newState: T) = > void] = [currentState, changeState]
      return tuple
    }

    const [counter, setCounter] = useState(10);
    setCounter(1000)

    const [title, setTitle] = useState("abc")
Copy the code

Type constraints on a function

Functions are an important part of JavaScript, and TypeScript allows us to specify the types of functions’ arguments and return values.

Definition of function types

    type FooFnType = () = > void
    function bar(fn: FooFnType) {
      fn()
    }
Copy the code

Type annotations for parameters

  • When declaring a function, you can add a type annotation after each argument to declare the type of argument accepted by the function.
  • When we define function parameters, the required parameters cannot be placed after the optional parameters.
    / / complains
    function foo(n1? :number, n2: string) {
      return n1 + n2
    }

    foo(9.'pp')
    // But when defining an attribute constraint for an object type, we can write the optional argument anywhere, just to indicate that the attribute is not provided
    typeobjType = { name? :string
      age: number
    }
Copy the code
  • We do not need to specify type annotations when passing function parameters that appear in higher-order functions, because the function parameters are automatically typed
    const names = ["abc"."cba"."nba"]
    // item is derived from the context of the item
    // Functions in context: you can do without type annotations
    names.forEach(function(item) {})Copy the code
  • When the type passed in is an object
    • We can specify it this way
    function printPoint(point: { x: number; y: number }) {
      console.log(point.x)
      console.log(point.y)
    }
    
    printPoint({ x: 123.y: 321 })
    Copy the code
    • We can also specify the optionality of the object properties through?To identify the
    // This means that we can pass without the z 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

Type annotation for the return value

  • When declaring a function, you can add a return value type annotation at the end of the function list.
  • As with variable type annotations, we generally don’t need a return type annotation because TypeScript infer the return type of a function from its return value.

Function overloading

Definition of function overloading:

Allows you to create multiple functions of the same name with different implementations. Calls to overloaded functions run their context-specific implementation, which allows a function call to perform different tasks depending on the context.

  • Multiple function definitions use the same function name
  • The number or type of function arguments must differ

Function overloading in TS differs from other programming languages in that it requires defining the type of function overloading before implementing the function.

This is the wrong way to implement overloading

    // Error implementing overloaded functions

    function p(n1: number, n2: number) {
      return n1 + n2
    }
    function p(n1: string, n2: string) {
      return n1 + n2
    }
    console.log(p(20.30))
Copy the code

The correct way to implement overloading

    // Define the overloaded type of the function
    // Function overloading: functions with the same name but different arguments are function overloading
    function add(num1: number, num2: number) :number; // No function body
    function add(num1: string, num2: string) :string;
    
    // Implement the internal logic of overloaded functions
    function add(num1: any, num2: any) :any {
      if (typeof num1 === 'string' && typeof num2 === 'string') {
        return num1.length + num2.length
      }
      return num1 + num2
    }

    const result = add(20.30)
    const result2 = add("abc"."cba")
Copy the code

The joint type

A variable, sometimes he can be assigned to multiple types of values, we can use | to split each type.

    const id: number|string|boolean = 2;
    console.log('id', id)
Copy the code

In fact, the optional type mentioned above can be regarded as a combination of type and undefined

message? :string ===> message: string | undefined
Copy the code

Cross type

Crossed types indicate that conditions for more than one type need to be satisfied. We can use ampersand to split each type.

    interface ISwim {
      swimming: () = > void
    }

    interface IFly {
      flying: () = > void
    }

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

    // If only one interface method is implemented, we can call the method directly, and ts automatically infer the type.
    const obj1: MyType1 = {
      // It is possible to implement both interfaces, or only one of them
      // flying() {},
      swimming(){},}const obj2: MyType2 = {
      // Both interface methods must be implemented
      swimming() {},
      flying(){},}Copy the code

When we cross over in development, we usually cross over object types. Merge objects

interface Colorful {
  color: string
}
interface IRun {
  running: () = > void
}

type NewType = Colorful & IRun

const obj: NewType = {
  color: 'red'.running: () = >{},}Copy the code

Type the alias

Sometimes when we write objects or more complex types. Passing a function as an argument, for example, can seem confusing and complicated. When the same object structure is used in multiple places, we need to write it many times. So, at this point we can use type to define a type alias for the object. Make it reusable and readable.

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

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

Types of assertions

Sometimes TypeScript doesn’t get specific Type information; we need to use Type Assertions. Generally used in the class more.

    class Person {}class Student extends Person {
      studying(){}}function sayHello(p: Person) {
    // Change the Person type to Student
      (p as Student).studying()
    }

    const stu = new Student()
    sayHello(stu)

Copy the code

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

Non-null type assertion!

When we write the following code, we will get an error during the compilation phase of ts execution: this is because the incoming message may be undefined, and the method cannot be executed.

function printMessageLength(message? :string) {
  console.log(message.length)
}

printMessageLength()
Copy the code

However, we can use non-null type assertions when we are sure that the parameter passed in has a value: a non-null assertion uses! , indicating that an identifier can be determined to have a value, skipping ts’s detection of it at compile time. If no value is passed, an error is reported.

 function printMessageLength(message? :string) {
  console.log(message! .length) } printMessageLength()// If we call a function and we pass in values, we will not get an error.
Copy the code

At this point, we can use the optional chain in ES11 and use the optional chain operator, okay? If the property of the object does not exist, it will short-circuit and return undefined directly. If it exists, the execution will continue.

 function printMessageLength(message? :string) {
  console.log(message? .length) } printMessageLength()// return undefined.
Copy the code

While we’re at it? Let’s have a look again. Student: Right?

He was added to the ES11. Null-value merge operator (??) Is a logical operator that returns the right-hand operand if the left-hand side of the operator is null or undefined, otherwise returns the left-hand operand. In fact he’s effect and | |, but | | usage in the if judgment itself, so later can use?? To replace the | | do short circuit operation.

    let message: string | null = 'Hello World'

    const content1 = message ?? Hello '1'
    const content2 = message ? message : Hello '2'
    const content3 = message || Hello '3'
    console.log(content1)
    console.log(content2)
    console.log(content3)
Copy the code

Literal type

In addition to the types we discussed earlier, literal types can also be used. This type can then assign the specified literal as a value. It only makes sense to use it with the union type.

    // 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

Type to reduce the

What is type narrowing?

We can change TypeScript execution paths with typeof padding === “number” statements. Within a given execution path, we can shrink a type that is smaller than when declared, a process called narrowing. Typeof padding === “number can be called Type Guards.

Common types of protection are as follows:

  • typeof
    // 1. The typeof typeof is reduced
    type IDType = number | string
    function printID(id: IDType) {
      if (typeof id === 'string') {
        console.log(id.toUpperCase())
      } else {
        console.log(id)
      }
    }
Copy the code
  • Equality diminishes (e.g. ===,! = =)
    type Direction = 'left' | 'right' | 'top' | 'bottom'
    function printDirection(direction: Direction) {
      / / 1. If judgment
      if (direction === 'left') {
        console.log(direction)
      }else if() {... }/ / 2. The switch of judgment
      switch (direction) {
        case 'left':
          console.log(direction)
          break
        case 'right':
          console.log(direction)
          break
        case 'top':
          console.log(direction)
          break
        case 'bottom':
          console.log(direction)
          break}}Copy the code
  • Instanceof, generally used for class judgment
    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
    // 4. in
    type Fish = {
      swimming: () = > void
    }

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

    function walk(animal: Fish | Dog) {
      if ('swimming' in animal) {
        animal.swimming()
      } else {
        animal.running()
      }
      // (animal as Fish).swimming()
    }

    const fish: Fish = {
      swimming() {
        console.log('swimming')
      },
    }

    walk(fish)
Copy the code

class

Js class knowledge will not be introduced. We’ll just cover some of the extensions to classes in typescript.

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.

Read-only property

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. Read-only attributes, however, can be assigned to in constructor. The property itself cannot be modified, but if it is an object type, the property in the object can be modified.

    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: stringage? :number
      readonlyfriend? : Personconstructor(name: string, friend? : Person) {
        this.name = name
        this.friend = friend
      }
    }

    const p = new Person("llm".new Person("jcl"))
    console.log(p.name)
    console.log(p.friend)

    // You cannot change friend directly
    // p.friend = new Person("hcy")
    if (p.friend) {
      // Name cannot be modified because name is read-only.
      p.friend.name = "zh"
      // But age can be changed
      p.friend.age = 30
    } 
    
    // Cannot be modified
    // p.name = "123"

Copy the code

Accessors (getters, setters)

Accessors can be used in cases where private properties are not directly accessible, or where we want to listen for getters and setters.

    class Person {
      // Define private attributes
      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('zh')
    p.name = 'llm'
    console.log(p.name)
Copy the code

An abstract class

As we know, 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, they cannot be created by new).
  • An abstract method must be implemented by a subclass, otherwise the class must be an abstract class.
    // We cannot pass in objects instantiated by our Shape class. Because Shape is an abstract class
    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))
Copy the code

Class as type

Classes can also be used as a type

    class Person {
      name: string = "zh"
      eating(){}}const p = new Person()

    // use class to constrain p1
    const p1: Person = {
      name: "llm".eating(){}}function printPerson(p: Person) {
      console.log(p.name)
    }

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

interface

Interface defines object types (read-only, optional)

You can declare object types, and you can specify readable properties readonly and optional properties, right?

    interface IInfoType {
      readonly name: string
      age: number.fn: () = > void
    }

    const info: IInfoType = {
      name: "zh".age: 20.fn() {
        console.log(name, age)
      }
    }
Copy the code

Defining index types

We can define key values and key names of the same type.

    // Use interface to define the index type
    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

Interfaces define function types

Interfaces can be used to define common properties and methods in objects, but they can also be used to define function types. There is no method body, only method signature. However, it is better to define function types through type aliases.

    // type CalcFn = (n1: number, n2: number) => number
    // 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

Inheritance of interfaces

Interfaces, like classes, can be inherited using the extends keyword. And can support multiple inheritance.

    interface ISwim {
      swimming: () = > void
    }

    interface IFly {
      flying: () = > void
    }

    interface IAction extends ISwim, IFly {}

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

Classes can implement interfaces

Once an interface is defined, it can be implemented by a class. If 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.

Implements the interface through implements.

    interface ISwim {
      swimming: () = > void
    }

    interface IEat {
      eating: () = > void
    }

    // Class implements the interface
    class Animal {}

    // Inheritance: only single inheritance can be implemented
    // Implementation: Implements interfaces. Classes can implement multiple interfaces
    class Fish extends Animal implements ISwim.IEat {
      swimming() {
        console.log('Fish Swmming')}eating() {
        console.log('Fish Eating')}}class Person implements ISwim {
      swimming() {
        console.log('Person Swimming')}}// Write some common APIS: interface oriented programming
    function swimAction(swimable: ISwim) {
      swimable.swimming()
    }

    // 1. All objects corresponding to classes that implement interfaces can be passed in
    swimAction(new Fish())
    swimAction(new Person())

    swimAction({ swimming: function () {}})Copy the code

Interface is different from type

  • When defining non-object types, type is usually recommended, such as Direction, Alignment, and some functions.

  • If you define an object type, then they are different:

    • Interfaces can repeatedly define properties and methods for an interface. Ts will merge the interface of the same name, and when we implement it, we need to implement merge into the interface.
        interface IFoo {
          name: string
        }
    
        interface IFoo {
          age: number
        }
    
        // We need to implement the above
        const foo: IFoo = {
          name: 'zh'.age: 18,}Copy the code
    • Type defines an alias, which cannot be repeated.
        // Duplicate definitions will result in an error
        type IBar = {
          name: string
          age: number
        }
    
        type IBar = {
        }
    Copy the code

Refer to the assignment

When we reference assignment objects to different interfaces, the TS internally handles the differences between different interface types without error. An error is reported if an object from a different interface is assigned to another interface.

    interface IPerson {
      name: string
      age: number
    }

    const info = {
      name: 'zh'.age: 20.address: 'Xinyang city',}// freshness erases, no errors
    const p: IPerson = info
    // This will result in an error because the assigned object type does not match the IPerson type
    const p1: IPerson = {
      name: 'zh'.age: 20.address: 'Xinyang city'
    }
Copy the code

Enumerated type

Enum is used to define enumeration types. In fact, it can be replaced by the union type.

  • Values of enumerated types are incremented from 0 by default.
  • Enumeration types (for numeric enumeration only) can also be evaluated in reverse, using subscripts to extract the corresponding enumeration value.
    enum Direction {
      LEFT,
      RIGHT,
      TOP,
      BOTTOM,
    }

    console.log(Direction[2]) // TOP
Copy the code
  • The value of an attribute of an enumeration type, which can be a number or a string.
  • No reverse mapping is generated for string enumerators.

The generic

The main purpose of software engineering is not only to build unambiguous and consistent apis, but also to make your code highly reusable: for example, we can encapsulate some apis with functions that help us do different things by passing in different function arguments.

The use of generics in functions

We used to type constrain function parameters and return values at the time of function definition, but now we can type constrain function parameters by generics. We give a generic variable as a parameter when we define it, and we pass in the generic variable type when we call the function. Make the type of the argument is also parameterizable. Generally, ts can automatically infer the type of the generic variable when we pass in a function parameter, so it does not display the passed generic type.

    function sum<Type> (num: Type) :Type {
      return num
    }

    // 1. Call method 1: an explicit incoming type
    sum<number> (20)
    sum<{name: string({} >name: "zh"})
    sum<any[] > ["abc"])
    
    // 2. Call method 2: type push to
    sum(50)
    sum("abc")
Copy the code

Also, we can define multiple generics. Note: either all or none of the types are passed in.

    function foo<T.E.O> (arg1: T, arg2: E, arg3? : O, ... args: T[]) {}
    
    // Either multiple types are passed in here, or none at all
    foo<number.string.boolean> (10.'abc'.true)
Copy the code

If we specify default types for generics in a function, we must specify them all, otherwise we will get an error. (This is an error, please ignore)

    // If one of the generic types is specified, the others must be specified as well.
    function foo<T = string.E = string.O = boolean> (arg1: T, arg2: E, arg3? : O, ... args: T[]) {}

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

We might see some common generic names in development:

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

The use of generics in interfaces

We can use generics in interfaces to allow the outside world to pass in specified types to constrain internal properties or methods. And it does not automatically infer the type of the generic type.

    interface IPerson<T1, T2> {
      name: T1
      age: T2
    }

    const p: IPerson<string.number> = {
      name: "zh".age: 20
    }
Copy the code

We can also specify the default type of a generic, and we can specify it partially.

    interface IPerson<T1, T2 = number> {
      name: T1
      age: T2
    }
    
    // Only the first type is passed in. The second type is the specified type
    const p: IPerson<string> = {
      name: 'zh'.age: 20,}Copy the code

The use of generics in classes

We can pass in a type after a class call or when we specify an instantiated object type. Also, TS can do type inference if no type is passed in. You can also specify a default type.

    class Point<T = number> {
      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')
Copy the code

Generic constraint

Sometimes we want the types passed in to have some commonality, but those commonalities may not be in the same type. At this point we can make the generic extends from the 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

Module parse

Type of lookup

We’ve written almost all of the typescript types up until now, but we also use a few other types:

    const image = document.getElementById('image') as HTMLImageElement
Copy the code

Are you wondering where our HTMLImageElement type comes from? Why would document even have a getElementById method?

This is where typescript’s rules for managing and finding types come in. We’ll start with another typescript file:.d.ts files

The typescript files we’ve written are.ts files, which eventually output.js files, which is where we usually write our code. There is another type of file, the.d.ts file, which is used to declare types. It simply does type detection and tells typescript what types we have.

So where does typescript look for our type declarations?

  • Built-in type declarations.
    • 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.
  • Externally define type declarations. These are usually type declarations that we need when we use some library, such as a third-party library.
    • Sometimes he installs third party packages, which he defines internally.d.tsFile. Take the AXIos library.

    • In most cases, third-party libraries do not provide built-in libraries.d.tsThe file, we can go throughThe linkFind the corresponding library.d.tsTo install.
  • Define your own type declarations.

Let’s look at custom type declarations.

The statement module

When do you need to define a declaration file yourself?

  • The third party library we use is a pure JavaScript library with no corresponding declaration file.You can declare the syntax of a module: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[]) :void
    }
Copy the code
  • We declare some types in our code that we can use directly elsewhere. Type declarations and implementations that declare variables/functions/classes etc. are written separately.
    // Declare variables/functions/classes
    declare let name: string
    declare let age: number
    // Declare the function
    declare function foo() :void/ / class declarationdeclare class Person {
      name: string
      age: number
      constructor(name: string, age: number)}Copy the code
  • Declare files, typescript doesn’t recognize imported image files, etc., so we need to declare too.
    // Declaration file. An error is reported when we import files such as images in the TS file.
    declare module '*.jpg'
    declare module '*.jpeg'
    declare module '*.png'
    declare module '*.svg'
    declare module '*.gif'
Copy the code
  • Declaring a namespace
    // Declare a namespace
    declare namespaceThe ${export function ajax(settings: any) :any
    }
Copy the code

A concrete implementation of the above type

  <script src="Https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
Copy the code
    let name = 'zh'
    let age = 20

    function foo() {
      console.log('foo')}class Person {
      name
      age
      constructor(name, age) {
        this.name = name
        this.age = age
      }
    }
    console.log(name)
    console.log(age)

    foo()

    const p = new Person('llm'.20)
    console.log(p)

    $.ajax({})
Copy the code