preface


Ts is already a must for the front end, and will only be more popular in the future, and will be applied more in the project!

Learn!

The first part of this article is more basic, the second half is more in-depth, I hope to finish reading patience, more or less, there will be harvest!

A brief introduction to TS


TypeScript is a superset of JavaScript that follows the ES6/ES5 specification and extends JavaScript syntax.

TypeScript’s biggest feature is its friendly prompt, type-checking of code to detect errors during coding and avoid online problems. Ts will not run directly in the browser and will eventually be compiled into JS.

Let’s get down to business

Second, TS environment configuration


1. Global installationTypeScriptfortsCompile.

NPM install typescript -g TSC --init # generates the tsconfig.json configuration fileCopy the code
TSC -- Watch # Monitor ts file changes to generate JS filesCopy the code

Install ts-node-g with the node environment: ① VScode plugin: code runner ② global install ts-Node-g

2. Build the tool environment configuration

Ts can be resolved in two ways:

  • Ts Plug-in Parsing
  • Babel parsing

rollup => rollup-plugin-typescript2

webpack => ts-loader babel-plugin-typescript

  • Install dependencies
npm install rollup typescript rollup-plugin-typescript2 @rollup/plugin-node-resolve rollup-plugin-serve -D
Copy the code

Rollup-plugin-typescript2 is a bridge between rollup and typescript. Rollup /plugin-node-resolve enable rollup to resolve third-party modules. Rollup-plugin-serve Starts the service.

  • Example Initialize the TS configuration file
npx tsc --init
Copy the code
  • A rollup. Config. Js configuration
import ts from 'rollup-plugin-typescript2'
import {nodeResolve} from '@rollup/plugin-node-resolve';
import serve from 'rollup-plugin-serve';
import path from 'path'
export default {
    input:'src/index.ts'.output: {format:'iife'.// umd, esm, cjs iife 
        file:path.resolve('dist/bundle.js'), 
        sourcemap:true
    },
    plugins:[
        nodeResolve({
            extensions: ['.js'.'.ts']
        }),
        ts({
            tsconfig:path.resolve(__dirname,'tsconfig.json')
        }),
        serve({
            open:true.openPage:'/public/index.html'.port:3000.contentBase:' ' // Indicates that the base directory is the root directory}})]Copy the code
  • Package. The json configuration
"scripts": {
    "dev": "rollup -c -w"
}
Copy the code

NPM run dev go!

Third, basic types


1. Boolean, numeric, and string types

let bool:boolean = true;
let num:number = 10;
let str:string = 'hello world';
Copy the code

2. Tuple type

The types correspond to each other and the number is fixed

let tuple: [string, number, boolean] = ['hello'.10.true]; // When initializing, assignments must be made according to the type definition
tuple.push('world') // Only defined types can be added
tuple[3] = 100; // Tuples cannot be changed by index
Copy the code

An array of 3.

Declares the element data type of an array

let arr1: number[] = [1.2.3];
let arr2: string[] = ['1'.'2'.'3'];
let arr3: (number | string)[] = [1.'2'.3];
let arr4: Array<number | string> = [1.'2'.3];
Copy the code

4. Enumeration types

  • Ordinary enumeration
enum LANG {
    REACT,
    VUE,
    ANGULAR
}
// {0: "REACT", 1: "VUE", 2: "ANGULAR", REACT: 0, VUE: 1, ANGULAR: 2}
Copy the code
// The compiled result
(function (LANG) {
    LANG[USER_ROLE["REACT"] = 0] = "REACT";
    LANG[USER_ROLE["VUE"] = 1] = "VUE";
    LANG[USER_ROLE["ANGULAR"] = 2] = "ANGULAR";
})(LANG || (LANG = {}));
Copy the code
  • Heterogeneous enumeration
enum LANG {
    REACT = 'react',
    VUE = 1,
    ANGULAR
}
// {"REACT": "react", "VUE": 1, "ANGULAR": 2}
Copy the code

Enumerations support backlifting, but only for indexes, and infer automatically.

  • Constant enumeration
enum LANG {
    REACT,
    VUE,
    ANGULAR
}
console.log(LANG.VUE, LANG[0]) // 1 REACT

const enum LANG {
    REACT,
    VUE,
    ANGULAR
}
console.log(LANG.REACT, LANG[0]) // 0 undefined
Copy the code

When const is added, an object is not generated, and backlift is not supported.

5. Any types

6. Null, and undefined

Null and undefined are subtypes of any type. If strictNullChecks is true, or in strictNullChecks mode, null and undefined cannot be assigned to other types. Null can only be assigned to null, and undefined can only be assigned to undefined.

let xx = number | boolean;
xx = null;
Copy the code

7. The void type

The value of void can only be null and undefined, and is generally used for the return value of a function.

let a: void; // a = undefined;
let b: () = > void; // Indicates that there is no return value, the return value is undefined
interface IC {
    new() :void; // Indicates that you do not care about the return value type
}
Copy the code

In strict mode, null cannot be assigned to void. Void is used in an interface to define a stereotype method in a class to indicate that the return value type is not concerned. In the function return value, the return value is undefined, that is, there is no return value.

8. Never type

A subtype of any type that represents a value that never occurs. You cannot assign values of other types to never.

/ / wrong
function error(message: string) :never {
    throw new Error("err");
}
// A never-ending loop
function loop() :never {
    while (true) {}}// The condition of never walking in
function fn(x:number | string){
    if(typeof x == 'number'){

    }else if(typeof x === 'string'){

    }else{
        console.log(x); // never}}Copy the code

9. Object Indicates the object type

Object indicates a non-primitive type. In addition to number, string, Boolean, symbol, null, and undefined outside type.

let create = (obj:object):void= >{}
create({});
create([]);
create(function(){})
Copy the code

Generic constraints make heavy use of the object type.

10. Unknown type

1) unknown type

Indicates that the type is unknown. Any type can be assigned to unknown type. It is the security type corresponding to any.

let unknown:unknown;
unknown = 'tianshi';
unknown = 18;
Copy the code

Attributes of the unknown type cannot be accessed. They cannot be used as functions or classes.

  • In the union typeunknown
type UnionUnknown = unknown | null | string | number;  // type UnionUnknown = unknown
Copy the code

The other types are combined with unknown, resulting in unknown types.

  • Cross typeunknown
type inter = unknown & null; // type inter = null
Copy the code

Other types are crossed with unknown, and the result is all other types.

2) unknown features
  • neverisunknownThe subtype of
type isNever = never extends unknown ? true : false; // type isNever = true
Copy the code
  • keyof unknownisnever
type key = keyof unknown; // type key = never
Copy the code
  • unknownThe type cannot be traversed
type IMap<T> = {
    [P in keyof T]: number
}
type t = IMap<unknown>; // type t = {}
Copy the code
  • unknownType cannot sumnumbertype+operation
let p1: unknown;
let p2: number;
let p = p1 + p2 // Type error
Copy the code

11. The Symbol type

Symbol means unique

const s1 = Symbol('key');
const s2 = Symbol('key');
console.log(s1 == s2); // false
Copy the code

12. BigInt type

BigInt is a value greater than 2^53-1

const num1 = Number.MAX_SAFE_INTEGER + 1;
const num2 = Number.MAX_SAFE_INTEGER + 2;
console.log(num1 == num2); // true

let max: bigint = BigInt(Number.MAX_SAFE_INTEGER);
console.log(max + BigInt(1) === max + BigInt(2)); // false
Copy the code

The number and bigInt types are incompatible.

Type assertion


1. Union type

// Common union type
let numOrStr: string | number;
let el: HTMLElement | null = document.getElementById('id');

// The literal type
// The content of the type is fixed. If the type is complex and we want to reuse it later, we can extract the type separately.
type IType = 'a' | 'b' | 'c';
let type1: IType = 'b';
let type2: IType = 'c';
Copy the code

2. Non-null assertions!

let el: HTMLElement | null = document.getElementById('id'); el! .innerHTML ='xxx';
Copy the code

3. The mandatory conversion types as | < >

Strong type, must ensure that the union type can be.

let xx = string | number | undefined;
(xx as string).split(' ');
(<string>xx).split(' '); // Conflict with JSX, not recommended
Copy the code

4. Double assertion

(xx as any) as boolean;
Copy the code

5. Function types


1. Two ways to declare functions

// function keyword, function declaration
function sum(a: string, b: string) :string {
    return a+b;
}
sum('a'.'b')

// Function expression
type Sum = (a1: string, b1: string) = > string;
let sum: Sum = (a: string, b: string) = > {
    return a + b;
};
Copy the code

Function overloading can only be written as a function declaration. Type aliases can only be written as function expressions.

2. Optional parameters

letsum = (a: string, b? : string):string= > {
    return a + b;
};
sum('a'); // Optional arguments must be at the end of other arguments
Copy the code

3. Default parameters

let sum = (a: string, b: string = 'b') :string= > {
    return a + b;
};
sum('a'); // The default argument must be at the end of the other arguments
Copy the code

4. Remaining parameters

constsum = (... args: string[]):string= > {
    return args.reduce((memo, current) = > memo += current, ' ')
}
sum('a'.'b'.'c'.'d');
Copy the code

5. Function overload

function toArray(value: number) :number[]
function toArray(value: string) :string[]
function toArray(value: number | string) {
    if (typeof value == 'string') {
        return value.split(' ');
    } else {
        return value.toString().split(' ').map(item= > Number(item));
    }
}
toArray(123); // Returns different results depending on the type of data passed in
toArray('123');
Copy the code

Six, class,


1. Define classes in TS

class Pointer{
    x: number = 1; // The declared variable is added to the instance. Attributes on the instance must be declared firsty! : number;constructor(x:number, y? :number, ... args:number[]){
        this.x = x;
        this.y = y asnumber; }}let p = new Pointer(100.200);
Copy the code

Properties on instances must be declared before being used. Arguments in constructors can take optional and residual arguments.

2. Modifiers in classes

  • pubicThe modifier

It can be accessed by itself, subclasses, and instances.

class Animal {
    constructor(public name: string, public age: number){}}class Cat extends Animal {
    constructor(name: string, age: number) {
        super(name, age);
        console.log(this.name,this.age); // Subclass access to Tom 18}}let p = new Cat('Tom'.18);
console.log(p.name,p.age); // The outer layer accesses Tom 18
Copy the code
  • protectedThe modifier

It can be accessed by itself and subclasses, but not by instances.

class Animal {
    constructor(protected name: string, protected age: number) {
        this.name = name;
        this.age = age; }}class Cat extends Animal {
    constructor(name: string, age: number) {
        super(name, age);
        console.log(this.name, this.age)
    }
}
let p = new Cat('Tom'.18);
console.log(p.name,p.age);// Cannot be accessed
Copy the code
  • privateThe modifier

Only the subclass and instance can access it.

class Animal {
    constructor(private name: string, private age: number) {
        this.name = name;
        this.age = age; }}class Cat extends Animal {
    constructor(name: string, age: number) {
        super(name, age);
        console.log(this.name, this.age); // Cannot be accessed}}let p = new Cat('Tom'.18); 
console.log(p.name,p.age);// Cannot be accessed
Copy the code
  • readonlyRead-only modifier

Only you can access it

class Animal {
    constructor(public readonly name: string, public age: number) {
        this.name = name;
        this.age = age;
    }
    changeName(name:string){
        this.name = name; // Read-only attributes can only be assigned by constructor}}class Cat extends Animal {
    constructor(name: string, age: number) {
        super(name, age); }}let p = new Cat('Tom'.18); 
p.changeName('Jerry');
Copy the code

3. Static properties and methods, property accessors

class Animal {
    static type = 'Mammals'; // Static attributes
    static getName() { // Static method
        return 'Animal';
    }
    private _name: string = 'Tom';

    get name() { // Attribute accessors
        return this._name;
    }
    set name(name: string) {
        this._name = name; }}let animal = new Animal();
console.log(animal.name); // Tom
console.log(Animal.getName()); / / animal
console.log(Animal.type); // 'mammal'
Copy the code

Static properties and methods can be inherited by subclasses

4. Super properties

class Animal {
    say(message:string){
        console.log(message);
    } 
    static getType(){
        return 'animals'}}class Cat extends Animal {
    say(){ // In the stereotype method, super refers to the stereotype of the parent class
        super.say('Meow the cat');
    }
    static getType(){ // Static method super refers to the parent class
        return super.getType()
    }
}
let cat = new Cat();
console.log(Cat.getType()) / / animals
console.log(cat.say()); / / the cat call
Copy the code

5. Class decorators

Decorator is a function. Don’t think of it as complicated.

1) Decoration class
function addSay(target:any){
    target.prototype.say = function(){console.log('say')}
}
@addSay
class Person { say! :Function
}
let person = new Person
person.say(); // say
Copy the code

Decoration class extensions can give class, need to open experimentalDecorators: true.

2) Decorate the attributes in the class
// target => Person.prototype
function toUpperCase(target:any,key:string){
    console.log(target, key);
    let value = target[key]; 
    Object.defineProperty(target,key,{
        get(){
            return value.toUpperCase();
        },
        set(newValue){
            value = newValue
        }
    })
}
// target => Person
function double(target: any, key: string) {
    let value = target[key];
    Object.defineProperty(target, key, {
        get() {
            return value * 2;
        },
        set(newValue) {value = newValue}
    })
}
class Person {
    @toUpperCase
    name: string = 'XiaoTianShi'
    @double
    static age: number = 10;
    getName() {
        return this.name; }}let person = new Person();
console.log(person.getName(),Person.age) // XIAOTIANSHI 20
Copy the code

Decorative properties can overwrite the content of the property. Decorated with instance properties, target points to the prototype of the class, decorated with static properties, target points to the class itself.

3) Decorate the methods in the class
function get(params: any) {
    return function (target:any,key:string,descriptor:PropertyDescriptor) {
        console.log(descriptor);
        / / {
        // value: [Function],
        // writable: true,
        // enumerable: true,
        // configurable: true
        // }

        // Modify the method defined in the class to change all arguments passed in the decorator method to string
        let oMethod = descriptor.value;
        descriptor.value = function (. args: any[]) {
            args = args.map(val= > {
                return String(val)
            });
            oMethod.apply(this, args); }}}class Person {
    name: string = 'TianShi'
    static age: number = 10;
    @get('Method entry')
    getName(. args: any[]) {
        console.log(args, this.name); // ['111', '111'] // TianShi}}let person = new Person();
console.log(person.getName(111.'111')); 
Copy the code

Decorates methods that can be overridden. For instance methods, target points to the prototype of the class; for static methods, target points to the class itself.

4) Decorate the parameters in the method
function addPrefix(params: any){
    return function(target:any,key:string,paramIndex:number){
        console.log(target,key,paramIndex, params, params[paramIndex]); // Person.prototype getName 0 uuid u
        // Extend attributestarget.expendProp = params; }}class Person {
    name: string = 'XiaoTianShi'prefix! :stringgetName(@addPrefix('uuid') prefix:string) {
        console.log(prefix); // -ts
        return this.name; }}let person: any = new Person();
console.log(person.getName('-ts')); // XiaoTianShi
console.log(person.expendProp); // uuid
Copy the code

Parameter decorator expressions are called as functions at run time, and you can use the parameter decorator to add some raw data to the prototype of the class. Receives three arguments: 1. Constructor for static members and prototype object for instance members. 2. Method name. Parameter The index in the parameter list of the function.

5) Decorator execution sequence

Property decorator => Method Decorator => Parameter Decorator 2 => Parameter Decorator 1 => Class Decorator 2 => Class Decorator 1

function logClass1(params:string) {
    return function(target:any) {
        console.log('Class decorator 1'); }}function logClass2(params:string) {
    return function(target:any) {
        console.log('Class decorator 2'); }}function logAttribute(params? :string) {
    return function(target:any, attr:any) {
        console.log('Property decorator'); }}function logMethod(params? :string) {
    return function(target:any, methodName:any, desc: any) {
        console.log('Method decorator'); }}function logParams1(params? :string) {
    return function(target:any, methodName:any, paramsIndex: any) {
        console.log('Parameter decorator 1'); }}function logParams2(params? :string) {
    return function(target:any, methodName:any, paramsIndex: any) {
        console.log('Parameter Decorator 2');
    }
}

@logClass1('hello')
@logClass2('world')
class HttpClient {
    @logAttribute()
    public apiUrl: string | undefined;
    constructor() {}

    @logMethod()
    getData() {}

    setData(@logParams1() param1:any, @logParams2() param2:any){}}let p:any = new HttpClient();
Copy the code

6. An abstract class

Abstract classes cannot be instantiated, only inherited. An abstract method must be implemented in an abstract class, only in a concrete subclass of the abstract class, and must be implemented.

abstract class Animal{ name! :string; abstract speak():void
}
class Cat extends Animal {
    speak(){
        console.log('Meow the cat'); }}class Dog extends Animal{
    speak():string{
        console.log('Bark!');
        return 'wangwang'}}Copy the code

When defining a type, void means that the return value of the function is null (regardless of the return value type).

Seven, interfaces,


Interface describes the shape and structure of an object, which is easy to reuse.

1. Function interface parameters

interface IPerson {
    name:string;
    age:number;
}
type IPerson = {name: string, age: number} | string;
const people = (obj:IPerson):string= >{
    return `${obj.name}This year,${obj.age}Years old! `
}

people('xiaotianshi'.18)
Copy the code

Function parameters are described and constrained through interfaces. Interfaces can be implemented and inherited by classes, but type cannot. Type can be a union type, interface is disgusting.

2. Function type interface

interface ISum {
    (a: string, b: string): string;
}
const sum: ISum = (a, b) = > {
    return a + b;
}
sum('1'.'2');
Copy the code

Restrict the parameter types and return value types of functions through interfaces.

3. Mixed types of functions

To define an attribute for a function, how should we describe its type? Using a counter example, each call is +1.

interface ICounter {
    (): number; // Restrict function types
    count: 0 // restrict attributes on functions
}
let fn: ICounter = (() = > {
    return fn.count++;
}) as ICounter;
fn.count = 0;
console.log(fn()); / / 0
console.log(fn()); / / 1
Copy the code

4. Object interface

// Read-only attribute
interface IVegetables {
    readonly color: string,
    size: string
}
// Optional attribute, union typeinterface IVegetables { price? : number,taste: 'sour' | 'sweet'
}
// Any attribute
interface IVegetables {
    [key: string]: any;
}
const tomato: IVegetables = {
    color: 'red'.size: '10'.taste: 'sour'.shape: 'circle'
}
In addition to arbitrary attributes, type assertions can also be used for redundant attributes
const tomato: IVegetables = {
    color: 'red'.size: '10'.taste: 'sour'.type: 'vegetables'
} as IVegetables;
// Only read attributes cannot be modified
tomato.color = 'green'; 
Copy the code

? Indicates an optional property. Readonly indicates that the property is read-only and cannot be modified. Interfaces with the same name will be merged, changing the original interface.

5. Any attribute can index the interface

interface Person {
    name: string;
    [key: string]: any
}
let p: Person = {
    name: 'xiaotianshi'.age: 18[Symbol()] :'high'
}
Copy the code

Some attributes can be restricted by any attribute, and the rest can be added or subtracted at will.

interface IArr {
    [key: number]: any
}
let p: IArr = {
    0: '1'.1: '2'.3: '3'
}
let arr: IArr = [1.'d'.'c'];
Copy the code

Indexable interfaces are used to identify arrays.

6. The class interface

interface Speakable {
    name: string;
    speak(): void;
}
interface ChineseSpeakable {
    speakChinese(): void
}
class Speak implements Speakable.ChineseSpeakable { name! : stringspeak() {}
    speakChinese(){}}Copy the code

A class can implement multiple interfaces, and a class must implement properties and methods in the interface

7. Interface inheritance

interface Speakable {
    speak(): void
}
interface SpeakChinese extends Speakable {
    speakChinese(): void
}
class Speak implements SpeakChinese {
    speakChinese(): void {
        throw new Error("Method not implemented.");
    }
    speak(): void {
        throw new Error("Method not implemented."); }}Copy the code

Constructor types

Classes can act as types, describing instances.

// type IPerson = new (name: string) => Person;
interface IPerson<T> {
    new (name: string): T
}
function createInstance<T> (clazz: IPerson<T>, name: string) {
    return new clazz(name);
}

class Person {
    age: 18;
    constructor(public name: string){}}class Dog {
    color: 'yellow';
    constructor(public name: string){}}let r = createInstance<Dog>(Dog, 'dog'); // r is of type Dog, ok. Come out color and name
Copy the code

Different ways to write type and interface. New () indicates that it is currently a constructor type. Why generics? Because the return value type is uncertain, we do not know if it is Dog or Person. The type of a class is used to describe instances.

Eight, generics


Generics are usually used to determine the type at runtime. Commonly used in functions, classes, interfaces, aliases.

1. Specify function parameter types

  • A single generic
const getArray = <T>(times: number, val: T): T[] => {
    let result: T[] = [];
    for (let i = 0; i < times; i++) {
        result.push(val);
    }
    return result;
}
getArray(3.3); // 3 => T => number
Copy the code
  • More generic
// Tuple switch type
function swap<T.K> (tuple: [T, K]) :K.T] {
    return [tuple[1], tuple[0]]}console.log(swap(['a'.'b']))
Copy the code

2. The way of function annotation

  • Type the alias
type TArray = <T, K>(tuple: [T, K]) => [K, T];
const getArray:TArray = <T, K>(tuple: [T, K]): [K, T] => {
    return [tuple[1], tuple[0]]
}
Copy the code
  • interface
interface IArray{
    <T,K>(typle:[T,K]):[K,T]
}
const getArray:IArray = <T, K>(tuple: [T, K]): [K, T] => {
    return [tuple[1], tuple[0]]
}
Copy the code

Type and keyof as a joint type, interface can be inherited and implemented, scalability is better.

3. Use of generic interfaces

interface ICreateArray<T> { // where T is passed in when the interface is used
    <U>(a: T, b: U): U[] // the U is passed in when the function is called
}
let createArray: ICreateArray<number> = <U>(times: number, value: U): U[] => {
    let result = [];
    for (let i = 0; i < times; i++) {
        result.push(value);
    }
    return result;
}
createArray(1.'xxx');
Copy the code

Generics are called at different times depending on where they come in. Put it before a function to indicate that the type is determined when the function is called, and after an interface to indicate that the type is determined when the interface is used.

4. Default generics

interface T2<T = string> {
    name: T
}
type T22 = T2;
let p: T22 = { name: 'tianshi' } // p is of type T2
Copy the code

A default generic is used to specify the default type of a generic, similar to a function default parameter.

5. Generics in classes

  • When creating the instance, provide the type
class MyArray<T>{ // T => number
    arr: T[] = [];
    add(num: T) {
        this.arr.push(num);
    }
    getMaxNum(): T {
        let arr = this.arr
        let max = arr[0];
        for (let i = 1; i < arr.length; i++) {
            let current = arr[i];
            current > max ? max = current : null
        }
        returnmax; }}let myArr = new MyArray<number>();
myArr.add(3);
myArr.add(1);
myArr.add(2);
console.log(myArr.getMaxNum());
Copy the code
  • Constructor type
interface IPerson<T> {
    new (name: string, age: number): T
}

const createClass = <T>(clazz: IPerson<T>, name: string, age: number) = > {
    return new clazz(name, age);
}

class Person {
    constructor(public name: string, public age: number){}}let r = createClass<Person>(Person, 'xxx'.18);
Copy the code

6. Generic constraints

  • Attribute constraints
interface IWithLength {
    length:number
}
const computeArrayLength = <T extends IWithLength.K extends IWithLength>(arr1: T, arr2: K): number => {
    return arr1.length + arr2.length;
}
computeArrayLength('123', {length: 3});
computeArrayLength([1, 2], '34');
Copy the code

They must both have the length attribute.

const sum = <T extends number>(a: T, b: T): T => {
    return (a + b) as T
}
let r = sum<number>(1, 2); 
Copy the code

The type must be number.

  • Object constraint
const getVal = <T extends object.K extends keyof T>(obj: T, key: K): T[K] => {
    return obj[key];
}
getVal({a: 1, b: 2}, 'b');
Copy the code

The second argument must be some key in the first argument.

Ix. Compatibility


The compatibility here is different from that of our browser. The compatibility of TS mainly depends on whether the structure is compatible, and the core is to consider security.

1. Compatibility of basic data types

let temp: string | number;
letnum! : number; temp = num;Copy the code

Temp has the type num, so it can be compatible, can be assigned.

let num: {
    toString(): string
}
let str: string = 'tianshi';
num = str;
Copy the code

Strings have the toString() method, so they are compatible and can be assigned.

2. Interface compatibility

interface IAnimal {
    name: string,
    age: number
}
interface IPerson {
    name: string,
    age: number,
    address: string
}
let animal: IAnimal;
let person: IPerson = {
    name: 'will'.age: 18.address: 'haidian'
};
animal = person;
Copy the code

Interfaces can be compatible only with the types required by the interfaces. People are animals, but animals are not necessarily people.

3. Function compatibility

Function compatibility, more is to compare parameters and return values.

  • parameter
let sum1 = (a: string, b: string) = > a + b;
let sum2 = (a: string) = > a;
sum1 = sum2
Copy the code

You can pass two, but you pass one, it’s safe. You can only pass one argument, but you gave two. It’s not safe.

type Func<T> = (item: T, index: number) = > void
function forEach<T> (arr: T[], cb: Func<T>) {
    for (let i = 0; i < arr.length; i++) {
        cb(arr[i], i); // both item and index are returned
    }
}
forEach([1.2.3].(item) = > { // If item is used, index is not used
    console.log(item);
});
Copy the code

An assignment function takes arguments less than or equal to the function being assigned, as opposed to an object.

  • The return value
type sum1 = () = > string | number
type sum2 = () = > string;

letfn1! : sum1;letfn2! : sum2; fn1 = fn2;Copy the code
type sum1 = () = > { name: string };
type sum2 = () = > { name: string; age: number };

letfn1! : sum1;letfn2! : sum2; fn1 = fn2;Copy the code

4. Contravariant covariant of functions

The arguments to the function are contravariant, and the parent class can be passed. The return value of the function is covariant and can return subclasses. (In non-strict mode, the parameters of the function are bidirectional covariant).

class Parent {
    address: string = 'China'
}
class Child extends Parent {
    money: number = 100
}
class Grandsom extends Child {
    name: string = 'Ming';
}
type Callback = (person: Child) = > Child
function execCallback(cb: Callback) {}// Return the father to the grandson
let fn = (person: Parent) = > new Grandsom;
execCallback(fn);
Copy the code

Argument, accepts Child, and passes Parent. Returns Grandsom instead of Child. Narrow the input parameter return to enlarge the return value range. The goal is safety.

So, this is an illustration of type compatibility that shows you how types can be used. From the application level, when the actual application needs Child, pass the Child, pass the Parent error.

5. Class compatibility

class Perent {
    name: string = 'tianshi';
    age: number = 18
}
class Parent1 {
    name: string = 'tianshi';
    age: number = 18
}
let parent: Perent = new Parent1;
Copy the code

Note: Whenever there is a private or protected modifier, the type is inconsistent. But inherited classes are compatible.

class Parent {
    protected name: string = 'tianshi';
    age: number = 18
}
class Child extends Parent {};let child: Parent = new Child;
Copy the code

6. Generic compatibility

interface MyType<T> { }
let obj1: MyType<string>;
let obj2: MyType<number>;
obj1 = obj2;
Copy the code

7. Compatibility with enumerations

enum USER1 {
    role = 1
}
enum USER2 {
    role = 1
}
letuser1! : USER1letuser2! : USER2 user1 = user2// Error syntax
Copy the code

Different enumeration types are not compatible.

X. Type protection


Type protection is the automatic identification of variable properties and methods by determining which code snippets are being executed.

1.typeofType of protection

function double(val: number | string) {
    if (typeof val === 'number') {
        val. // You can click on numeric properties and methods
    } else {
        val. // You can click string properties and methods}}Copy the code

2.instanceofType of protection

class Cat { eat(){}}class Dog { drink(){}}const getInstance = (clazz: { new(): Cat | Dog }) = > {
    return new clazz();
}
let r = getInstance(Cat);
if (r instanceof Cat) {
    r / / the cat
} else {
    r / / the dog
}
Copy the code

3.inType of protection

interface Fish {
    swiming: string,
}
interface Bird {
    fly: string,
    leg: number
}
function getType(animal: Fish | Bird) {
    if ('swiming' in animal) {
        animal // Fish
    } else {
        animal // Bird}}Copy the code

4. Recognize union types

Identify the type by adding a unique custom attribute.

Add a class attribute to determine whether the WarningButton type or DangerButton type is used.

interface WarningButton {
    class: 'warning'
}
interface DangerButton {
    class: 'danger'
}
function createButton(button: WarningButton | DangerButton) {
    if (button.class == 'warning') {
        button // WarningButton
    } else {
        button // DangerButton}}Copy the code

5. Null protection?? ||

const addPrefix = (num? : number) = > {
    num = num || 1.1; // Make sure the outer values have true values
    let out = num.toFixed(); / / outer scope does not need to use the optional chain, because | | has to ensure that have value.
    function prefix(fix: string) {
        returnfix + num? .toFixed()/ /? . The inner scope still needs to use optional chain judgment
    }
    return prefix('zxd');
}
console.log(addPrefix());
Copy the code

Note: TS cannot detect internal function variable types.

6. User-defined type protectionis

interface Fish {
    swiming: string,
}
interface Bird {
    fly: string,
    leg: number
}
function isFish(animal: Fish | Bird) :animal is Fish {
    return 'swiming' in animal
}
function getAniaml(animal: Fish | Bird) {
    if (isFish(animal)) {
        animal // You can click on the attributes of the fish
    } else {
        animal // You can click the bird properties
    }
}
getAniaml({ swiming: 'swim' });
Copy the code
function isString(val: any) :val is string {
    return Object.prototype.toString.call(val) === '[object String]';
}

let str = '123';
if (isString(str)) {
    str
}
Copy the code

The is keyword, called a type predicate, is used to determine whether a variable belongs to an interface or type. If you need to encapsulate a type judgment function, it should be the first thing on your mind. Animal is Fish, val is string Returns a Boolean, that is, the return value is a Boolean.

7. Integrity protection

Integrity protection to ensure that all code logic is covered. It relies primarily on never, taking advantage of never’s inability to reach the final result, to ensure code integrity.

interface ICircle { kind: 'circle', r: number } interface IRant { kind: 'rant', width: number, height: number } interface ISquare { kind: 'square', width: number } type Area = ICircle | IRant | ISquare const isAssertion = (obj: never) => { } const getArea = (obj: Area) => {switch (obj.kind) {case 'circle': return 3.14 * obj.r ** 2+ case 'rant':
+ return obj.width * obj.height
+ case 'square':
+ return obj.width * obj.widthdefault: return isAssertion(obj); }} getArea({kind: 'square', width: 100});Copy the code

All logic must be implemented.

Type inference

Ts has great type inference and does not require us to define all the types we use.

1. Assignment inference

let str = 'tianshi';
let age = 18;
let boolean = true;
Copy the code

Infer at assignment, the variable type is inferred from the assignment.

2. Return value inference

Automatically infer function return value types.

function sum(a: string, b: string) {
    return a + b;
}
let r = sum('a'.'b');
Copy the code

3. Function inference

Deduce the parameter type and return value type from left to right.

type Sum = (a: string, b: string) = > string;
const sum: Sum = (a, b) = > a + b;
Copy the code

4. Attribute inference

Infer the type of the attribute from its value.

let person = {
    name: 'tianshi'.age: 18
}
let { name, age } = person;
Copy the code

5. Type backward

Use the Typeof keyword to deduce variable types.

let person = {
    name: 'tianshi'.age: 18
}
type Person = typeof person; // {name: string, age: number}
Copy the code

6. Index access operator

Access through []

interface IPerson {
   name: string,
   age: number,
   job: {
       address: string
   }
}
type IJob = IPerson['job'] ['address']; // type IJob = string;
Copy the code

Note: The type of interface can only be accessed through [].

7. Type mapping

interface IPerson {
   name: string,
   age: number
}
type IMapPerson = { [key in keyof IPerson]: IPerson[key] } // type IMapPerson = { name: string, age: number };
Copy the code

The keyof keyword is used to obtain the key defined by the interface, similar to object.keys () in js. [key in keyof IPerson]: IPerson[key] Identifies the key that traverses the IPerson and assigns the value type.

Cross types

Intersection Type is the merging of multiple types into a single Type. To extend a property from an existing type, use a cross type.

In general, we use the ampersand to implement crossover types.

interface Person1 {
    handsome: string,
}
interface Person2 {
    high: string,
}
type P1P2 = Person1 & Person2;
let p: P1P2 = { handsome: 'handsome'.high: 'high' };
Copy the code

The crossover type is similar to the intersection in mathematics, where you have two groups of people, one is tall, one is handsome, and we want to find the intersection, the tall and handsome person.

function mixin<T.K> (a: T, b: K) :T & K {
    return{... a, ... b } }const newType = mixin({ name: 'tianshi' }, { age: 18 }) 
// newType: { name: string } & { age: number }
Copy the code
interface IPerson1 {
    name: string,
    age: number
}
interface IPerson2 {
    name: number
    age: number
}
type person = IPerson1 & IPerson2
letname! : neverlet person: person = { name, age: 11 };
Copy the code

The value of string & number between the two attributes is never. Because you can’t have an attribute that is both a string and a number. The TS core is that for safety, cross types can be assigned to types that are not crossed before.

Type of conditions


1. Condition type Basic use

Conditional judgments are implemented using extends and ternary expressions

interface Fish {
    name1: string
}
interface Water {
    name2: string
}
interface Bird {
    name3: string
}
interface Sky {
    name4: string
}
type Condition<T> = T extends Fish ? Water : Sky;
let con1: Condition<Fish> = { name2: 'water' };
Copy the code

2. Conditional type distribution

let c: Condition<Fish | Bird> = { name2: 'water' };

// The types are distributed in turn, eventually taking the combined type as the result. Is equivalent to:
type c1 = Condition<Fish>;
type c2 = Condition<Bird>;
type c = c1 | c2
Copy the code

An example: When the name attribute is passed, the age attribute is passed. When the name attribute is not passed, the age attribute is optional.

interface ISchool1 {
    name: string; age: number } interface ISchool2 { age? : number; size: string; } type School<T> = Textends { name: string } ? ISchool1 : ISchool2;
let school: School<{name: 'xxx'} >// let school: ISchool1
Copy the code

3. Built-in condition types

  • ExcludeRule out type
type Exclude<T, U> = T extends U ? never : T;
type MyExclude = Exclude<'1' | '2' | '3'.'1' | '2'>  // MyExclude = '3'
Copy the code
  • ExtractPump type
type Extract<T, U> = T extends U ? T : never;
type MyExtract = Extract<'1' | '2' | '3'.'1' | '2'> // MyExtract = "1" | "2"
Copy the code
  • NonNullableNot empty detection
type NonNullable<T> = T extends null | undefined ? never : T
type MyNone = NonNullable<'a' | null | undefined> // MyNone = 'a'
Copy the code

Infer type

Infer represents the type variable to be inferred in the extends condition statement. (Only used in extends condition statements)

  • ReturnTypeReturn value type
type ReturnType<T> = T extends(... args: any) => infer R ? R : never;Copy the code

In this conditional statement, Infer R represents the return value of the function to be inferred.

If T can be assigned to (… Args: Any => infer R, and the results are: Args: any) => infer THE return value R in type R, otherwise never is returned.

type ReturnType<T> = T extends(... args: any) => infer R ? R : neverfunction getUser(name: string, age: number) {
    return { name: 'tianshi'.age: 18 }
}
type MyReturn = ReturnType<typeof getUser> // MyReturn = { name: string, age: number };
type MyString = ReturnType<string> // MyString = never
Copy the code
  • ParametersThe parameter types
type Parameters<T> = T extends(... args: infer P) => any ? P : any;Copy the code

In this conditional statement, Infer R represents the type of parameter to be inferred.

If T can be assigned to (… Args: infer P) => any, and the infer result is (… Args: Infer P) => parameter P of type ANY, otherwise return any.

function getUser(name: string, age: number) {
    return { name: 'tianshi'.age: 18 };
}
type MyParams = Parameters<typeof getUser>; // MyParams = [string, number]
type MyString = Parameters<string>; // MyString = any
Copy the code
  • ConstructorParametersConstructor parameter type
type ConstructorParameters<T> = T extends { new(... args: infer P): any } ? P : never;Copy the code

In this conditional statement, Infer P represents the type of constructor parameter to be inferred.

If T can be assigned to new (… Args: infer P): any, and the result is new (… Args: infer P): constructor parameter P in any type, otherwise return never.

class Person {
    constructor(name: string, age: number) { }
}
type MyConstructor = ConstructorParameters<typeof Person> // MyConstructor = [string, number]
type MyString = ConstructorParameters<string> // MyString = never
Copy the code
  • InstanceTypeInstance type
type InstanceType<T> = T extends { new(... args: any): infer R } ? R : any;Copy the code

In this conditional statement, Infer R represents the instance type to be inferred.

If T can be assigned to new(… Args: any): infer R, and the result is new(… Args: any): infer R constructor parameter in type R, otherwise return any.

class Person {
    constructor(name: string, age: number) { }
  }
type MyInstance = InstanceType<typeof Person>; // MyInstance = Person
type MyString = InstanceType<string>; // MyString = any
Copy the code

5. Infer the practice

  • Converts an array type to an associative type
type ElementOf<T> = T extends Array<infer E> ? E : never;
Copy the code

In this conditional statement, Infer E represents the array element type to be inferred.

Infer E> if T can be assigned to Array

, the type of each entry in the Array

is returned; otherwise, never is returned.

type TupleToUnion = ElementOf<[string, number, boolean]>;  // TupleToUnion = string | number | boolean;
type TupleString = ElementOf<string>;  // TupleString = never;
Copy the code
  • Converts the arguments of two functions to cross types
type ToIntersection<T> = T extends ([(x: infer U) = > any, (x: infer U) = > any]) ? U : never;
Copy the code

In this conditional statement, Infer U represents the type of function parameter to be inferred.

To assign T1 and T2 to x, the value of x is the intersection of T1 and T2.

type T1 = { name: string };
type T2 = { age: number };
type t3 = ToIntersection<[(x: T1) = > any, (x: T2) = > any]>  // t3 = T1 & T2
type t4 = ToIntersection<[string, string]> // t4 = never
Copy the code

Built-in types

1.partialConvert optional properties

type Partial<T> = { [K inkeyof T]? : T[K] }Copy the code

The idea is to iterate through all the properties and make them optional.

interface Company {
    num: number
}
interface Person {
    name: string,
    age: string,
    company: Company
}
type PartialPerson = Partial<Person>; // { name: string, age: string, company: Company }
Copy the code

Note: Depth conversion is not possible.

Implement a depth conversion, continuing the depth conversion if the value is an object

type DeepPartial<T> = {
    [K inkeyof T]? : T[K]extends object ? DeepPartial<T[K]> : T[K]
}
type DeepPartialPerson = DeepPartial<Person>;
Copy the code

2.RequiredConvert required attributes

type Required<T> = {[K inkeyof T]-? :T[K]}Copy the code

Similar to Paritial, Partial converts Required to optional, Required uses -? Change optional to required.

interface Company {
    num: number
}
interface Person {
    name: string,
    age: string,
    company: Company
}
type PartialPerson = Partial<Person>;
type RequiredPerson = Required<PartialPerson>
Copy the code

3.ReadonlyThe transformation reads only properties

type Readonly<T> = { readonly [K in keyof T]: T[K] }
Copy the code

This is done by adding a readOnly modifier to each property to make it readable.

interface Company {
    num: number
}
interface Person {
    name: string,
    age: string,
    company: Company
}
type RequiredPerson = Readonly<Person>
Copy the code

4.PickSelect the desired attribute from the existing type

type Pick<T, K extends keyof T> = { [P in K]: T[P] }
Copy the code

To analyze, T represents the type of the object passed in and K extends Keyof T represents the type of the constraint K, which must be an attribute of T. [P in K]: T[P] selects the attributes and types belonging to K from T and returns them.

interface Company {
    num: number
}
interface Person {
    name: string,
    age: string,
    company: Company
}
type PickPerson = Pick<Person, 'name' | 'age'> // pickPerson = { name: string, age: string }
Copy the code

5.RecordRecord type

type Record<K extends keyof any, T> = { [P in K]: T }
Copy the code

The K extends Keyof any generic constraint means that K is of type string, number, or symbol. (The type of key that can be used as an object)

[P in K]: T indicates that the key is one of string, number, or symbol, and the value is the generic T passed in.

let person: Record<string, any> = { name: 'tianshi'.age: 18 };
Copy the code

We often use the Record type to represent the mapping type.

function map<T extends keyof any.K.U> (obj: Record<T, K>, callback: (item: K, key: T) => U) :Record<T.U> {
    let result = {} as Record<T, U>
    for (let key in obj) {
        result[key] = callback(obj[key], key)
    }
    return result
}

const r = map({ name: 'xiaotianshi'.age: 18 }, (item, key) = > {
    return item
});
// r = Record<"name" | "age", string | number>
Copy the code

Sentence by sentence analysis:

  1. <T extends keyof any, K, U>Three type parameters, T is constrained tostring, number, symbolOne of these types.
  2. obj: Record<T, K>The key that defines the object obj isTType and the value isKType.
  3. callback: (key: T, value: K) => UDefines the type of callback, and the type of the input key isT, value is of typeK, the return value type isU.
  4. Record<T, U>Defines the type of object to return. The key isTType and the value isUType.

In this case, through the participation {name: ‘xiaotianshi, age: 18} T can be inferred is type string, K is the string | number. Through the let result = {} as Record < U > T, can infer the types of U is a callback function return value type, actually like K type, and string | number.

6.OmitIgnore the attribute

type Exclude<T, U> = T extendsU ? Never: T; type Pick<T, Kextends keyof T> = { [P in K]: T[P]; }
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
Copy the code

Exclude

excludes K from keyof T. Pick

> and then select the attributes from T from which K was excluded.
,>

let person = {
    name: 'tianshi'.age: 18.address: 'haidian'
}
type OmitAddress = Omit<typeof person, 'address'> // type OmitAddress = { name: string; age: number; }
Copy the code

Ignore the Address attribute in Person, exclude the Address attribute, and then pick out the desired attributes in Person.

15. Packing and unpacking


1. Install package

type Proxy<T> = {
    get(): T,
    set(value: T): void
}
type Proxify<T> = {
    [P in keyof T]: Proxy<T[P]>
}
let props = {
    name: 'tianshi'.age: 18
}
function proxify<T> (obj: T) :Proxify<T> {
    let result = {} as Proxify<T>;
    for (let key in obj) {
        let value = obj[key];
        result[key] = {
            get() {
                return value
            },
            set: (newValue) = > value = newValue
        }
    }
    return result
}
let proxyProps = proxify(props);
// let proxyProps: Proxify<{ name: string; age: number; } >
Copy the code

2. Unpacking

function unProxify<T> (proxyProps: Proxify<T>) :T {
    let result = {} as T;
    for (let key in proxyProps) {
        let value = proxyProps[key];
        result[key] = value.get()
    }
    return result
}
let proxy = unProxify(proxyProps);
// let proxy: { name: string; age: number; }
Copy the code

Custom types


1.Diffimplementation

let person1 = {
    name: 'tianshi'.age: 18.address: 'China'
}
let person2 = {
    address: 'China',
}
type Diff<T extends object, K extends object> = Omit<T, keyof K>
type DiffPerson = Diff<typeof person1, typeof person2>
// type DiffPerson = { name: string; age: number; }
Copy the code

2.InterSectionintersection

let person1 = {
    name: 'tianshi'.age: 18.address: 'China'
}
let person2 = {
    address: 'China',
}
type InterSection<T extends object, K extends object> = Pick<T, Extract<keyof T, keyof K>>
type InterSectionPerson = InterSection<typeof person1, typeof person2>
// type InterSectionPerson = { address: string; }
Copy the code

3.OverwriteAttribute to cover

If an existing attribute exists, the new attribute type is overridden

type OldProps = { name: string, age: number, visible: boolean };
type NewProps = { age: string, other: string };

type Diff<T extends object, K extends Object> = Omit<T, keyof K>
type InterSection<T extends object, K extends object> = Pick<T, Extract<keyof T, keyof K>>
type Overwrite<T extends object, K extends object, I = Diff<T, K> & InterSection<K, T>> = Pick<I, keyof I>
type ReplaceProps = Overwrite<OldProps, NewProps>
// type ReplaceProps = { name: string; age: string; visible: boolean; }
Copy the code

4.MergeObject to merge

Combine two object types.

type OldProps = { name: string, age: number, visible: boolean };
type NewProps = { age: string, other: string };

type Compute<A extends any> = { [K in keyof A]: A[K] };
type Merge<T, K> = Compute<Omit<T, keyof K> & K>;
type MergeObj = Merge<OldProps,NewProps>
// type MergeObj = { name: string; visible: boolean; age: string; other: string; }
Copy the code

Modules and namespaces


By default, we write code in a global namespace.

1. The module

File modules: Having import or export at the root of your TypeScript file creates a local scope in that file.

/ / a.t s export
export default 'a';

/ / index. Ts import
import name from './index';
Copy the code

2. Namespacenamespace

Namespaces can be used to organize code and avoid naming conflicts within files.

  • Use of namespaces
export namespace zoo {
    export class Dog { eat() { console.log('zoo dog'); }}}export namespace home {
    export class Dog { eat() { console.log('home dog'); }}}let dog_of_zoo = new zoo.Dog();
dog_of_zoo.eat();
let dog_of_home = new home.Dog();
dog_of_home.eat();
Copy the code
  • Namespaces are used nested
export namespace zoo {
    export class Dog { eat() { console.log('zoo dog'); }}export namespace bear{
        export const name = 'bear'}}console.log(zoo.bear.name);  / / bear
Copy the code

Variables exported from a namespace can be used by the namespace.

Type declaration


1. Declare global variables

1) Common type declarations
declare let age: number;
declare function sum(a: string, b: string) :void;
declare class Animal {}; declareconst enum Seaons {
    Spring,
    Summer,
    Autumn,
    Winter
}
declare interface Person {
    name: string,
    age: number
}
Copy the code

Type declarations are removed at compile time without affecting actual code execution.

  • An example of declaring a jQuery type

JQuery was introduced through an external CDN and is intended to be used directly in code.

declare const $: (selector: string) = >{ height(num? : number):voidwidth(num? : number):void
};
$(' ').height();
Copy the code
2) Namespace declaration
declare namespace jQuery {
    function ajax(url: string, options: object) :void;
    namespace fn {
        function extend(obj: object) :void}}jQuery.ajax('/'{},);
jQuery.fn.extend({});
Copy the code

Namespace indicates that a global variable contains many child properties. You do not need to declare properties or methods inside the namespace.

2. Type declaration file

Type declaration files end in.d.ts, and by default all files ending in.d.ts are looked for when the project is compiled.

// jquery.d.ts
declare const $: (selector: string) = >{ height(num? : number):voidwidth(num? : number):void
};

declare namespace jQuery {
    function ajax(url: string, otpions: object) :void;
    namespace fn {
        function extend(obj: object) :void}}Copy the code

3. Prepare third-party declaration files

Configuration tsconfig. Json

"moduleResolution": "node"."baseUrl": ". /"."paths": {
    "*": ["types/*"]}Copy the code
  • Jquery Declaration file
// types/jquery/index.d.ts

declare function jQuery(selector: string) :HTMLElement;
declare namespace jQuery {
    function ajax(url: string) :void
}
export = jQuery;
Copy the code
  • Events module declaration file

Use:

import { EventEmitter } from "events";
var e = new EventEmitter();
e.on('message'.function (text) {
    console.log(text)
})
e.emit('message'.'hello');
Copy the code

Declaration Document:

export type Listener = (. args: any[]) = > void;
export type Type = string | symbol

export class EventEmitter {
    staticdefaultMaxListeners: number; emit(type: Type, ... args: any[]): boolean; addListener(type: Type,listener: Listener): this;
    on(type: Type, listener: Listener): this;
    once(type: Type, listener: Listener): this;
}
Copy the code

4. Module import and export

import $ from 'jquery'  // Applies only to export default $
const$=require('jquery'); // No declaration file can use the require syntax directly
import * as $ from 'jquery'  // In order to support the Commonjs specification and AMD specification export = jquery
import$=require('jquery')  // export = jquery is used in the commonJS specification
Copy the code

5. Third party declaration documents

@types is a convention prefix that all third party declared type libraries carry.

npm install @types/jquery -S
Copy the code

Lookup specification:

  • Node_modules/jquery/package types field in json
  • node_modules/jquery/index.d.ts
  • node_modules/@types/jquery/index.d.ts

Extend global variable types


1. Extend local variables

You can use interfaces to extend existing types.

interface String {
    double(): string
}
// String.prototype.double = function () {
// return this as string + this;
// }
let str = 'tianshi'; // You can click double
Copy the code
interface Window {
    mynane: string
}
console.log(window.mynane)
Copy the code

2. Global extension within the module

declare global {
    interface String {
        double(): string;
    }
    interface Window {
        myname: string
    }
}
Copy the code

3. Declare the merger

Two separate declarations with the same name are eventually merged into a single declaration, which has the features of the original two declarations.

1) Merge interfaces with the same name
interface Animal {
    name: string
}
interface Animal {
    age: number
}
let a: Animal = { name: 'tianshi'.age: 18 };
Copy the code
2) Merge of namespaces
  • The extension class

Add static members to a class

class Form { }
namespace Form {
    export const type = 'form'
}
console.log(Form.type); // form
Copy the code
  • Extension methods
function getName() { }
namespace getName {
    export const type = 'form'
}
console.log(getName.type); // form
Copy the code
  • Extended enumerated type
enum Seasons {
    Spring = 'Spring',
    Summer = 'Summer'
}
namespace Seasons {
    export let Autum = 'Autum';
    export let Winter = 'Winter'
}
console.log(Seasons.Autum) // Autum
Copy the code
3) Cross type merge
import { Store } from 'redux';
type StoreWithExt = Store & {
    ext: string
}
let store: StoreWithExt;
Copy the code

4. Generate a declaration file

Set tsconfig.json to true to generate the declaration file.

"declaration": true
Copy the code

The resources


  • Understand TypeScript in depth
  • Ts Chinese Document