In a nutshell, TypeScript’s interface

● Through the study of the first two chapters, we basically have an introduction to TS

● But we will find that we seem to be missing something about type restrictions

● We will continue to study this one

Interface

● Beginners may not understand it when they hear this name

● Those who have been in touch with front-end and back-end interactions may be confused by this name and easily confused

● However, don’t get entangled, forget everything you have directly, he is just a name

● Just like this thing, wife cake, where is the wife, is just a name

● So what exactly does the interface do?

○ In fact, it is just a type restriction method used to restrict non-basic data

● Recalling the previous type constraints, we find that

○ There is no good restriction method for objects, functions, classes, etc.

○ Is there really no, no

○ Interface is one of them

Interface first experience

● Consider the following example

let user: { name: string } = {}

● So this piece of code will prompt an error

● Then we need to modify the code, there needs to be a name attribute when assigning values

let user: { name: string } = { name: 'Qianfeng front end' }

● Then there is no problem

● Continue to the next example

let user: { name: string } = { name: 'Qianfeng front end' }
let person: { name: string } = { name: 'The leader in the front-end training industry' }

● We will find that the type constraints of the user variable and the person variable use exactly the same content

○ But I need to write one by one

○ According to the laziness of our programmers, why can’t we just write this thing once?

○ must be possible

● This thing is called an interface

○ We can take this type restriction and write it as an interface

○ It is much more convenient to use

● Writing in the form of interface

interface Info {
    name: string
}

let user: Info = { name: 'Qianfeng front end' }
let person: Info = { name: 'The leader in the front-end training industry' }

○ interface : A keyword defining an interface in TS

○ Info: interface name (capitalization is recommended)

● Is it suddenly clear

Various properties of the interface

Basic interface attributes

● It is to restrict the data types of various attributes in the interface

interface Info {
    name: string
    age: number
    gender: boolean
    hobby: string[]
}

● This interface is a basic interface restriction

○ must contain a name attribute, and it is of string type

○ must contain an age attribute, and it is of type number

○ must contain a gender attribute, and it is of boolean type

○ must contain a hobby property, and it is an array of strings

Optional attributes

● We can make some attributes optional

interface Info {
    name: string
    age: number
    gender: boolean
    hobby: string[]
    city?: string
}

● This is where an optional attribute is set

○ The city attribute is optional, if the city attribute is added, it must be a string type

Read-only attribute

● We can also set some properties not to be modified

● When you need to write properties in the interface, use the readonly keyword

interface Info {
    name: string
    age: number
    gender: boolean
    hobby: string[]
    city?: string
    readonly nationality: string
}

● After this definition is completed, the value of the nationality attribute cannot be modified after it is defined

Additional attributes

● Here we will find a problem

○ That is, if I use an interface to restrict a data, then I must write all possible attributes

○ But what if I can only confirm some attributes and others are not sure?

● Additional attributes can be used at this time

interface Info {
    name: string
    age: number
    gender: boolean
    hobby: string[]
    city?: string
    readonly nationality: string
    [props: string]: any
}

● This means that in addition to the properties already listed here, other key-value pairs can also be added

○ But the key must be a string type

○ Values can be of any type

● This extra attribute is actually not recommended

○ First: We’d better accurately grasp the data type restrictions we wrote ourselves

○ Second: In this way, our restrictions are not very meaningful

Index interface

● Indexed interfaces generally use interfaces to constrain an array

interface StringArray {
  [index: number]: string
}

● Let’s analyze this interface first

○ Using extra attributes

○ You can add any number of attributes

○ But the key must be a number type

If it is an object data structure, then the key can only be of string type

Array data type, key is number type

○ value must be a string

● So this interface is restricted to be an array of strings

● In fact, this is equivalent to the way we limit the array is the same

interface StringArray {
  [index: number]: string
}
let list: StringArray = [ 'hello' ]

// Equivalent to

let list2: string[] = [ 'world' ]

Function interface

● Let’s think about it, in fact, the definition of the function is nothing more than two parts

○ parameters

○ return value

● So a function interface is to limit the parameters and return value of the function.

interface SearchFunc {
  (x: number, y: string): string
}

● Analyze a wave

○ This restriction requires two parameters

One is of type number

One is of type string

○ also limits the return value

Must be of type string

○ Then this data type must be a function

● But this interface is generally used to restrict function expressions

○ does not apply to declarative functions

interface SearchFunc {
  (x: number, y: string): string
}

const fn: SearchFunc = function (x, y) {
    return x + y
}

Interface inheritance

● Interfaces can also be inherited

● Also using the extends keyword

interface Person {
  name: string
  age: 18
}

// Student interface inherits from Person interface
interface Student extends Person {
  classRoom: number
}

Class interface

● Why do I put the class interface at the end, because it is very complicated

Class observation and analysis

● Let’s first write a simple class for analysis

class Student {
    constructor (name, age) {
        this.name = name
        this.age = age
    }

    sayHi () {
        console.log(`Hello, My name is ${ this.name }`)
    }
}

● Let’s see how to restrict a class

○ Restricted calls must be used in conjunction with the new keyword

○ There is a constructor in the class, which needs to accept parameters and limit what kind of object the returned instance is

○ How many parameters are passed when we call this class, and what are their types

○ How many methods are on the prototype of the class

● So many dimensions are needed to restrict a class type data

Class interface

● First of all, we need to learn a new interface specification, which is called class interface

● The class interface is dedicated to the class

● Take a look first

// object interface, limit the instance object
interface StudentInstance {
    name: string
    age: number
}
// class interface, limit constructor
interface StudentConstructor {
    // The return value of the constructor must be an object that meets the restrictions of the StudentInstance instance
    new (name: string, age: number): StudentInstance
}

● To use an interface for a class, you need to use the implements keyword

class Student implements StudentConstructor {
  constructor (name: string, age: number) {
    this.name = name
    this.age = age
  }
}

● It looks very good, and it is very simple

● But after writing it, I found out that it was full of mistakes

● Let me analyze it for you

○ The StudentConstructor interface seems to be a class interface, but in fact it only limits the new keyword and the return value type. It cannot be said that it is a class, it is more like a function, so it is obviously not good for us to limit a class

○ The Student class is not a function, but a class, and the constructor inside is a constructor function. Then this constructor has no instance when it is not called, so you can’t add name and age attributes reasonably

● everything is a problem, so what should I do

● At this time, if we want to make all restrictions better, we need to use factory functions

○ and also requires two interfaces

○ a restricted instance object

○ a constrained constructor

● Do not rush to add TS restrictions, first write the class as a factory pattern

//Define the factory function
// function createStudent( class, parameter 1, parameter 2 ) {}
function createStudent( ctro, name, age ) {
    return new ctro( name, age )
}

● In other words, we need to put the class into the factory function to call

○ Our factory function needs to accept a class, and also accept the parameters required by this class

○ Perform instantiation operation in the factory function, and then return

● Next we can add interface constraints

// Instance interface, limit instance object
interface StudentInstance {
  name: string
  age: number
  sayHi(): void
}

// class interface, limit constructor
interface StudentConstructor {
  new (name: string, age: number): StudentInstance
}

// factory function
function createStudent( ctro: StudentConstructor, name: string, age: number ): StudentInstance {
    return new ctro( name, age )
}

○ The ctro parameter of the factory function must be a class that satisfies the StudentConstructor interface

○ The return value of the factory function must be an instance object that satisfies the StudentInstance interface

○ Through these two points, the members of the instance object of the class are limited, and it will not work if there are too many

Because the factory function can only accept these data

If there are too many, an error will occur when calling the factory function

● Final writing class

// Instance interface, limit instance object
interface StudentInstance {
  name: string
  age: number
  sayHi(): void
}

// class interface, limit constructor
interface StudentConstructor {
  new (name: string, age: number): StudentInstance
}

// factory function
function createStudent( ctro: StudentConstructor, name: string, age: number ): StudentInstance {
    return new ctro( name, age )
}

// define class
class Person implements StudentConstructor {
    name: string
    age: number

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

    sayHi (): void {}
}

// start using
let s1 = createPerson(Student, 'Qianfeng front end', 10)
console.log(s1)

● At this point, a real class restriction is done

● It is indeed very troublesome, so we have relatively few restrictions on the class during the development process

● Because the class itself is a limitation