–strictPropertyInitialization

When the parameter is turned on, the calSS property must have an initial value defined in the constructor. You can add it after the property! To turn off the prompt.

class BadGreeter{
    // Property 'name' has no initializer and is not definitely assigned in the constructor.
    name: string
}
Copy the code

The constructor

overloading

class Point {
    constructor(x:number, y:number);
    constructor(s:string)
}
Copy the code

Note: constructors cannot have type arguments; Constructors cannot return types.

get/set

1. Only get, no set —-> readonly

2. The set argument has no type and the type is automatically inferred from the return value of GET

3. Get /set must have the same Member Visibility, that is, private, public, protected

Note: In TS 4.3 set/get can have different types of value.

implement

Classes must satisfy a specific interface, and multiple interfaces can be implemented.

class C implements A, B{
    // 
}
Copy the code

Pay attention to

1. Implement only checks that the class can be used as an interface. Mehtod’s type is not changed by Implement.

An error will be reported below. It would be intuitive to assume that the argument s to the check method must be a string. But this Implement does not actually change the type of mteHOD in the class. S will be stabilized to any.

interface Checkable{
    check(name: string): boolean;
}

class NameChecker implements Checkable{
    check(s){
        returnt s.toLowercse() === 'ok'
    }
}
Copy the code

2. Optional properties

interface A{ x: number; y? : number; } class C implement A{x = 0} cosnt C = new C(Copy the code

extends

Derived classes inherit all the attributes and methods of the base class and can be extended.

Method Overriding Overriding Methods

Derived classes can override the methods of the base class, but the methods must have the same interface. Error reported below.

class Base{ greet(){ console.log("Hello, World!" )}} class Drived extends Base{greet(name: string){console.log(name)}}Copy the code

Class initialization order

1. Initialize base class fields

2. Base class constructor initialization

3. Initialize the derived class fields

4. Initialize the derived class constructor

Inheritance of built-in types –> applies to ES5

In ES5, the derived class this is created by the derived class and then modified by the base class. ES6 and later, the this of the derived class is created by the base class and modified by the derived class (In Depth ES6, p. 204).

Therefore :(this causal inference is purely personal and welcome criticism)

1. In ES5, some methods of derived classes may not exist

2. The instanceof operator is invalid when applied to derived classes and their instances. ( new MsgError() ) instanceof MsgError —> false

class MsgError extends Error{
    constructor(m:string){
        super(m);
    }
    sayHello(){
        return this.message
    }
}
Copy the code

Rescue method (IE10 and before not working)

Manually adjust the prototype chain

Class MsgError extends Error{constructor(m:string){super(m) object.setPrototyeof (this, MsgError extends Error{constructor(m:string){super(m) MsgError.prorotype) } }Copy the code

Note: Subclasses of MsgError also set the prototype chain manually

In ES6, the derived class modifies this created by the base class, and the derived class constructor returns the modified this. The performance in TS is the same as in ES6, but for TS –> ES5 and below, the older syntax does not support this feature, so manually adjust the prototype chain.

Class visibility Member Visiblity

Public: Class properties and methods can be accessed anywhere outside the class

Protected: Methods and attributes of the base class can only be accessed from subclasses, not from outside the base class

The following situations behave differently in different OOP languages. In TS/C#/C++, the following f2 method of the Derived2 class is illegal. This is because the protected property of the base class is accessed directly.

class Base {
    protected x: number = 1
}
class Derived1 extends Base{
    protected x: number = 5
}
class Derived2 extends Base{
    f1(other: Derived2){
        other.x = 10
    }

    // Property 'x' is protected and only accessible through an instance of class 'Derived2'. 
    // This is an instance of class 'Base'.
    f2(other: Base){
        other.x = 10
    }
}
Copy the code

Private: Attributes and methods can only be accessed inside a class

In TS, a class of instances in which a method of one instance can access the private members of the rest. Seems to be the opposite of private behavior?

Java, C# and other languages don’t.

class A{
    private x = 10
    public sameAs(other: A){
        // work
        return other.x === this.x
    }
}
Copy the code

JavaScript private properties:Developer.mozilla.org/en-US/docs/…

Static members

Can only be called by the class constructor, which adds a bunch of properties and methods.

Static members can also be decorated with plublic, protected, and private.

Function properties such as name, length, call, etc. cannot be defined as static members.

Static class

There are no static classes in TS

JAVA, C# and other languages do not allow methods and attributes to exist independently of class, so you can only achieve TS/JS functions through static class methods.

Class MyStaticClass{static doSomething() {}} class MyStaticClass{static doSomething() {}} function doSomething() { MyHelperObject = { dosomething() {} }Copy the code

A generic class

Static method types: Static members of TS are not generic. Consider the reverse, if the Box. DefaultValue of an instance of Box below is set to a string. Then another instance of Box. DefaultValue will have a string value instead of a number.

class Box<T>{
    // Static members cannot reference class type parameters.
    static defaultValue:T
}
Copy the code

The runtime runtime

TS does not change the runtime logic of JS, so it can behave in the same weird way as JS.

What ‘s this in JS?

Arrow function

The arrow function’s this is lexical scope.

1. It can ensure that the value of this is always correct to avoid some weird behaviors

Each instance of a class that uses the arrow function saves the value of this

3. Super.getname cannot be used in derived classes. So the way the arrow function is written is not saved on the prototype chain

class MyClass{
    name = "MyClass"
    getName = () =>{
        return this.name    
    }
}
const c = new MyClass()
const g = c.getName

// Prints "MyClass" instead of crashing
console.log(g())
Copy the code

this parameters

When this is used as an argument to the function, TS erases this.

Function fn(this: SomeType, x:number){} function fn(x :number){}Copy the code

In Method, the method context is guaranteed to be correct by passing the this parameter of type MyClass. Similarly, at runtime, the this parameter is erased. Similarly, executing getName in the Global Context returns an error.

class MyClass{
    name = "MyClass"
    getName(this: MyClass){
        return this.name
    }
}

const c = new MyClass()
c.getName()

// crash
const g = c.getName
g()
Copy the code

This type –> this Types

In TS, classes can use the this type.

class Box{
    content = string = ""
    sameAs(other:this){
        return other.content === this.content
    }
}

class DerivedBox extends Box {
    otherContent: string = "?"
}
const base  = new Box
const derived = nwe DerivedBox
derived.sameAs(base)
Copy the code

This is the type guard

Use this in combination with other type guarding to shrink the target object to a specific type.

In the following case this is Networked & this is understood as this is (Networked & this). After the isNetwork() function executes, it changes the type of this, so the FileRep class has the type of Networked, that is, shrinking the object to a specific type.

class FileSystemObejct{
    isFile(): this is FileRep{
        return this instanceof FileRep
    }
    isDirectory():this is Directory {
        reutn this instanceof Directory
    }
    isNetworked(): this is Networked & this{
        return this.networked
    }
    constructor(public path: string, private networked: bolean){}
}

class FileRep extends FileSystemObject{
    constructor(path:string, public content:string){
        super(path, false)
    }
}

class Directory extends FileSystemObject{
    children: FileSystemObejct[]
}

interface Networked{
    host: string
}

const fso: FileSystemObject = new FileRep("foo/bar.text", "foo")

if(fso.isFile()){
    // FileRep
    fso.content;
}else if(fso.isDirectory()){
    // Directory
    fso.children
}else if (fso.isNetworked()){
    // Networked & FileSystemObject
    fso.host
}
Copy the code

Common usage

In this case, use this is to remove the undefined type of value.

class Box<T>{ value? : T hasValue(): this is {value: T}{ return this.value ! == undefined } } const box = new Box() // (property) Box<unknow>.value? : unknown box.value = "Gameboy" if(box.hasValue()){ // value: unknown box.value }Copy the code

Parameter Properties

Instead of assigning values to constructor variables, TS creates class attributes of the same type as the arguments and assigns values when the constructor is executed.

class Params{
    cosntructor(
        public readonly x: number,
        protected y: number,
        private z: number
    ){
        // no body necessary
    }
}

const a = new Params(1, 2, 3)
// work
console.log(a.x)

// crash
console.log(a.z)
Copy the code

Class Expressions

The following class expression has the same effect as declaring a class directly, except that the class name can be omitted from the expression.

const someClass = class<T> { content:T; constructor(value:T){ this.content = value; }}Copy the code

Abstract Classes and Members

An abstract method or property does not need to provide its implementation and can only exist in an abstract class. Abstract classes cannot be instantiated directly and are usually used as base classes. Its derived class must implement its class’s abstract method or an error is reported.

abstract class Base{
    abstract getName():String;
    printName(){
         console.log(`hello, ${this.getName()}`)
    }
}

// crash
const b = new Base()

class Derived extends Base{
    getName(){
        return "world";
    }
}

const d = new Derived();
// work
d.printName()
Copy the code

In some cases, you might want to take the constructor of a class and create an instance of the class, but an error will be reported when you encounter an abstract class.

Below, the street above abstract class Base

function greet(ctor: typeof Base){
    // crash 
    const instance = new ctor()
    instance.printName()
}

function greet1(ctor: new () => Base){
    const instance = new Ctor()
    instance.printName()
}

// work
greet(Derived)
// crash
// Cannot assign an abstract constructor type to a non-abstract constructor type.
greet(Base)
Copy the code

Relationships between classes

For the most part, TS will just compare the structure of the class.

class Point1{
    x = 0;
    y = 0;
}
class Point2{
    x = 0;
    y = 0;
}
// work
const p: Point1 = new Point2()

class Person{
    name: string;
    age: number;
}
class Employee{
    name: string;
    age: number;
    salary: number;
}
// work
const p1: Person = new Employee()
// crash
const p2: Employee = new Person()
Copy the code

Empty Class: An Empty Class has no members. In a structured type system, an Empty Class is the superclass of any object.

class Empty{}
function fn(x: Empty){
    // ...
}

// All OK!
fn(window)
fun({})
fn(fn)
Copy the code

reference

www.typescriptlang.org/docs/handbo…