In the former

Any application that can be implemented in javascript will eventually be implemented in javascript.

In the actual project, when we call a function written by others, the function does not leave any write-off. At this time, we need to find out the meaning of the call parameter of this function, and we need to look inside the function.

Sometimes we maintain a public function, you sweat to optimize a parameter type, but don’t know how many references, is not very worried, you modify the error of other functions.

All of this is because javascript is a dynamically weakly typed language. They are very tolerant of the types of variables and do not create a structured contract between these variables and their callers. If you develop without type constraints for a long time, you will lose “type thinking” and develop bad programming habits, which is one of the shortcomings of front-end development. Thankfully, the open source community has been working to address this issue, with Facebook releasing Flow back in 2014 and Microsoft releasing Typescript 1.0 that same year. Both are committed to providing static type checking for Javascript, and now that the years have passed, Typescript is clearly evolving better.

What is TypeScript?

TypeScript is officially a superset of Javascript with a type system that can be compiled into pure Javascript. Here are three key points to note:

  1. Type checking

    TypeScript does strict static type checking at compile time, which means you can spot potential pitfalls at the coding stage.

  2. Language extension

    TypeScript will include features such as asynchronous operations and decorators from ECMASript 6 and future proposals, as well as borrowing features such as interfaces and abstract classes from other languages.

  3. Tool attribute

    TypeScript compiles to standard Javascript and runs on any browser or operating system without any runtime overhead. In this sense, TypeScript is more of a tool than a language.

Why use TypeScript?

Other benefits of using TypeScript include Visual Studio Code’s powerful auto-completion, navigation, and refactoring capabilities, which allow interface definitions to replace documentation directly, as well as improving development efficiency and reducing maintenance costs. More importantly, Typescript helps teams reinvent “type thinking.” Interface providers are forced to think about API boundaries. They go from being code writers to code designers.

What is a strongly typed language

In strongly typed languages, when an object is passed from a calling function to the called function, its type must be compatible with the type declared in the called function – Liskove,Zilles 1974

function Test1() {
    Test2(a)
}
function Test2(b) {
    // b can be assigned to a, and the program works fine
}
Copy the code
  • Strongly typed languages: It is not allowed to change the data type of a variable unless a cast is performed.

  • Weakly typed languages: Variables can be assigned different data types

Statically typed language: The types of all variables are determined at compile time

  1. The compile phase determines the attribute offset
  2. Use offset access instead of attribute name access
  3. Offset information sharing
  • Extremely strict on type
  • Find errors immediately
  • Good runtime performance
  • Since the document

Dynamically typed language: The types of all variables are determined at execution time

  1. Property offsets are calculated dynamically while the program is running
  2. Extra space is required to store attribute names
  3. A copy of the offset information for all objects is saved
  • Very relaxed about types
  • Bugs can be hidden for months or even years
  • Poor runtime performance
  • Readability is poor

TS compilation principle

Q: TypeScript can be translated into JS, but that doesn’t mean TS is a compiled language, right? So why compile? Why not choose translation, such words; So what does TS compilation look like?

A: Translation is a simple mapping, while compilation involves complex transformations and is more precise. Compilation broadly refers to the process of converting a source language into a target language. For example, the TypeScript compiler scans source code, converts it into an abstract syntax tree, and then converts it to JavaScript. Narrowly defined compilation refers to the translation of source languages into machine code. Languages that require such translation are often called compiled languages (such as C++), while TypeScript’s outgrowth JavaScript is interpreted.

Never and void

In JS, void is the operator that allows any expression to return undefined. Undefined is not a reserved word

// Undefined can be declaratively assigned
(function() { 
    const undefined = 0; 
    console.log(undefined)
})()
Copy the code

Void 0 ensures that our return value is undefined

// never
let error = () = > {
    throw new Error('error')}Copy the code

A function that never returns a value if it throws an error returns a value of type never

Object type interface

In practice, the array returned by the back end might add some data

We find that TS does not report any errors because TS adopts a duck style, which is a dynamic language style. A more figurative way of saying this is that a bird can be considered a bird if it looks like a duck, walks like a duck and quacks like a duck. Back in TS, we are allowed to pass an object as long as it meets the necessary conditions of the interface, even if it passes extra fields through type checking.

But if we pass in object literals, TS checks for additional fields

If we use object literals to pass values, we use an assertion. Type assertion means we explicitly tell the compiler that the object literal is of type Result, so that the compiler can bypass type checking

Type assertions can also be written like this

However, we recommend using the first method because the following method can create ambiguity in React.

The index sign

We can also use index signatures

This is a string index signature, which means that using any string to index a List can result in any result. This allows lists to support multiple attributes.

Digital index

The implication is that if you index StringArray with any number you get a string structure

String index

The implication is that if you index an Item with any string you get a string

After this declaration, we can no longer declare a member of type number

Because the two signatures can be intermixed, for example, you can add a digital index signature to Item

So you can either index Item by number or you can index Item by string, but it’s important to note that the return value of the numeric index signature must be a subtype of the return value of the string index signature, because javascript does type conversion, converts number to string, This preserves type compatibility.

For example, if we change the return value of the digital index signature to number, then this is incompatible with string.

So take a type that is compatible with number, such as any.

Function type interface

Define it by Function

function fn1(x: number, y: number) {
    return x + y
}
Copy the code

Defined by a variable

let fn2: (x: number, y: number) = > number
Copy the code

Defined by a type alias

type fn3 = (x: number, y: number) = > number
Copy the code

Defined by interface

interface fn4 {
    (x: number, y: number): number
}
Copy the code

Mixed-type interface

Defines the interface

interface lib {
    (): void // indicates that this class is a function that returns void
    version: string, / / property
    toDo(): void / / method
}
Copy the code

implementation

let lib: lib = (() = > {}) as lib
lib.version = '1.0'
lib.toDo = () = > {}
Copy the code

Create multiple instances

function getLib() {
    let lib: lib = (() = > {}) as lib
    lib.version = '1.0'
    lib.toDo = () = > {} 
    return lib
}
let lib1 = getLib()
lib1.version
lib1.toDo()
let lib2 = getLib()
lib2.version
lib2.toDo()
Copy the code

Function overloading

class A {
  sum(a: number, b: number) {
    returna + b; }}class B extends A {
  sub(a: number, b: number) {
    returna - b; }}function maker() :B;
function maker(p: string) :A;
function maker(p? : string) {
  if (p) {
    return new A();
  }
  return new B();
}

const instane = maker();
instane.sub(1.2);

const instane2 = maker("ss");
instane2.sum(1.2);
Copy the code

When the TS compiler deals with overloads, it looks up a list of overloads and tries to match the first definition, and if it doesn’t match, it looks down, so we’ll put the easiest to match first.

assertions

type NumGenerator1 = () = > number;

function myFunc1(numGenerator1: NumGenerator1 | undefined) {
  constnum1 = numGenerator1! (a);constnum2 = numGenerator1! (a); }Copy the code

Use assertions to make the compiler pass the check, though this is not recommended and overloading should be used instead

overloading

type NumGenerator2 = () = > number;
function myFunc2() :undefined;
function myFunc2(numGenerator2? : NumGenerator2) {
  if (numGenerator2) {
    const num1 = numGenerator2();
    constnum2 = numGenerator2(); }}Copy the code

optional

type NumGenerator3 = () = > number;
function myFunc3(numGenerator3: NumGenerator3 | undefined) {
  constnum1 = numGenerator3? . (); }Copy the code

class

In general, ts classes overwrite JS classes and introduce other new features

class Cat{
    constructor(name:string) {
        // this.name = name} name? : stringrun(){}}Copy the code

In both TS and ES, the properties of a class member are instance properties, not stereotype properties, and the methods of a class member are instance methods.

inheritance

class ChildCat extends Cat {
    constructor(name: string, public color: string) {
        super(name)
    }
}
Copy the code

Be sure to call super in the constructor

The modifier

Public The default is public, meaning it is visible to everyone

Private Private member, can only be called from the class itself, cannot be called by instance, cannot be called by subclass

Protected members that can only be accessed from a class or subclass, not from an instance of the class

Constructor can also add protected to indicate that the class cannot be instantiated and can only be inherited

Readonly must be initialized, just like instance properties

In addition to class members, you can also add modifiers to constructor parameters, which automatically make the parameters properties of the instance and thus omit the class definition.

class ChildCat extends Cat {
    constructor(name: string, public color: string) {
        super(name)
    }
}
Copy the code

Static: the static modifier of a class. Static members can also be inherited

An abstract class

There are no abstract classes in ES. This is ts’s extension of an abstract class, which can only be inherited but cannot be instantiated. In an abstract class, you can define a method that has a concrete implementation, so that subclasses don’t have to implement it and reuse the method. It is also possible to specify no concrete method implementation in an abstract class, which constitutes an abstract method. The nice thing about abstract methods is that you know there are other implementations in the subclass, so there’s no need to implement them in the superclass.

abstract class Animal {
    eat() {
        console.log('eat')
    }
    abstract sleep(): void
}
class Chicken extends Animal {
    sleep() {
        console.log('sleep')}}const chicken = new Chicken()
chicken.eat()
Copy the code

polymorphism

The so-called polymorphism is to define an abstract method in the parent class, in a number of subclasses have different implementation of the method, when the program runs, according to different objects, perform different operations, to achieve the binding of the runtime

class Cattle extends Animal {
    sleep() {
        console.log('Cattle sleep')}}const cattle = new Cattle()
const animals: Animal[] = [chicken, cattle]
animals.forEach(o= > {
    o.sleep()
})
Copy the code

Chain calls

The whole point of chain calls is that the invoked method returns an instance of itself

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

class Myflow extends WorkFlow {
    next() {
        return this}}new Myflow().next().step1().next().step2()
Copy the code

The relationship between type and interface

An interface can constrain what attributes a class member has and their types

interface Human {
    name: string;
    eat(): void
}
Copy the code

A class implementing an interface must implement all properties and methods declared in the interface

class Asian implements Human {
    constructor(name: string) {
        this.name = name
    }
    name: string
    eat(){}}Copy the code

Interfaces can constrain only public members of a class

Inheritance of interfaces

Interfaces can inherit from each other like classes, and one interface can inherit from multiple interfaces

interface Man extends Human {
    run(): void
}
interface Child {
    cry(): void
}
interface Boy extends Man,Child {}

const boy: Boy = {
    name: ' '.run() {},
    eat() {},
    cry(){}}Copy the code

As can be seen from interface inheritance, interface inheritance can be separated from reusable interfaces, or multiple interfaces can be combined into one interface

Interface inheritance class

Interfaces can inherit interfaces, but also inherit classes, which is equivalent to the interface to the class members are abstracted out, that is, only the class member structure, and no concrete implementation

class Auto {
    state = 1
}
interface AutoInterface extends Auto {

}
Copy the code

So the AutoInterface implies the state property, and all you need to implement this AutoInterface is a class member and the state property

class C implements AutoInterface {
    state = 1
}
class Bus extends Auto implements AutoInterface {}Copy the code

We don’t need to implement the state property in this example, because Bus is a subclass of Auto that naturally inherits the state property. It is important to note that when the interface removes the members of the class, it removes not only the public members, but also the private and protected members.

Generic functions and generic interfaces

A lot of times we want a function or a class that can support multiple data types and have a lot of flexibility

function print(value: string) :string {
    console.log(value)
    return value
}
Copy the code

Function overloading

function print(value: string) :string
function print(value: string[]) :string[]
function print(value:any) {
    console.log(value)
    return value   
}
Copy the code

The joint type

function print(value: string | string[]) :string | string[] {
    console.log(value)
    return value
}
Copy the code

Any type

function print(value: any) {
    console.log(value)
    return value
}
Copy the code

The any type creates another problem. The any type loses some information, namely the constraints between types

The generic concept

Data types are not predetermined; the specific type is determined at the time of use

function log<T> (value: T) :T {
    console.log(value)
    return value
}
log<string[]>(['a'.'b'])
log(['a'.'b'])
Copy the code

We can not only define a function with generics, but also define a function type

type Log = <T>(value: T) = > T
const myLog: Log = log
Copy the code

A generic interface

This is equivalent to the way type aliases are defined, but currently the generics constrain only one function. Generics can also constrain other members

interface Log1 {
    <T>(value: T): T
}
Copy the code

All members of the interface are then constrained by generics

It is important to note that when generics constrain the entire interface, we must specify a type at implementation time

let myLog1: Log2<number> = log
myLog1(1)
Copy the code

If you do not specify a type, you can specify a default type in the interface definition

interface Log3<T = string> {
    (value: T): T
}
let myLog2: Log3 = log
myLog2('s')
Copy the code

Generic summary

Treat generic variables and function parameters the same; generics are just parameters of another dimension, parameters that represent types rather than values

Generic classes and generic constraints

A generic class

Much like generic interfaces, generics can constrain the members of a class, but it is important to note that generics cannot be applied to static members of a class

class Ame<T> {
    run(value: T) {
        console.log(value)
        return value
    }
}
const ame = new Ame<number>()
ame.run(1)
Copy the code

When no type argument is specified, value can be any value

const ame1 = new Ame()
ame1.run({a: 1})
ame1.run('ss')
Copy the code

Type constraints

interface Length {
    length: number
}
function print<T extends Length> (value: T) :T {
    console.log(value, value.length)
    return value
}
Copy the code

The parameter needs to have a length attribute

print([1])
print('ss')
print({length: 1})
Copy the code

Benefits of generics

  • Functions and classes can easily support multiple types, increasing the extensibility of programs
  • No need to write multiple function overloading, lengthy joint type declaration, enhance code readability
  • Flexible control of constraints between types