16
头图

Preface

Talk about why you should learn TypeScript?

  1. From a development perspective, TypeScript as a strongly typed language, has type constraints on attributes. In daily development, unnecessary BUG caused by parameter types is reduced. When you are using a function encapsulated by a colleague, the type does not know how to pass. When developing TS , it will have a very friendly type prompt. Then you know what parameters the function needs to pass, and what type of parameter is.
  2. In terms of project structure, the use of TypeScript can well control the project. By establishing the type management of each module, the types in the project can be managed through interface or type assertions. The types are used in the corresponding modules. When the project needs to be updated iteratively, only Need to make changes to the corresponding module type.
  3. From the perspective of the front-end overall view, the three major frameworks of the community have already been combined with TypeScript , and the community is also very complete. It has passed the should learn TypeScript or not.

Last year, many friends hesitated whether to learn TypeScript , and many were misled by articles posted by community friends, TypeScript is AnyScript .

TypeScript a bit of a learning cost for friends who have not been exposed to strongly typed languages, and when using TypeScript for development, the code may be bloated in the early stage, making you think that there are a lot of useless code, but in the later stage, you can feel it TypeScript brings you fun.

Learning TypeScript also gives you a bit of an advantage in the workplace. When you change jobs, if you have used the TypeScript combination framework to do some projects, the interviewer will also give priority to you, and your salary will also increase.
There is still a long way to go to the front end, and the frequency of new technologies/framework is very fast. In the end, it is still inseparable from JavaScript .

Next, let's take a look at TypeScript . This article is an explanation of the standard TypeScript document, and in a simpler vernacular, how to use TypeScript with .

Start map

TypeScript

One, the installation environment

#npm install -g typescript

1.1 VSCode configuration automatic compilation file

#1. 在目录下  
    tsc --init   自动生成 tsconfig.json 
    tsconfig.json 下 outdir 是输出的路径
#2.  任务--- 运行任务   监视 tsconfig.json

Second, the basic grammar

2.1 Array

Define use
// 第一种定义方法   let 数组名:类型[] = []
var arr:number[] = [1,2,3];
console.log(arr);
// 第二种定义方法    let 数组名:Array[类型] = []
var newArr:Array<number> = [1,2,3];
console.log(newArr)

2.2 Tuples

It represents the number of elements and an array of element types, and each element type can be different.
Access tuple length and elements
var strArr:[number,string,boolean] = [22,'测试',false]
console.log(strArr.length)
console.log(strArr[0])
#它只能按类型的优先顺序输入内容,否则报错

2.3 Enumeration

enum type is a supplement to the JavaScript standard data type.

  • If the index is not specified for the enumeration, the default is 0, and the value can be obtained enumeration object [index]
  • If the enumeration index is specified as a string, its value can be obtained enumeration. property
enum Sex {Man,Woman}

let m:Sex = Sex.Man;
console.log(m) //0


let w: string = Sex[1]
console.log(w) //Woman


enum Animal {Dog = 3, Cat, Tiger};

console.log(Animal[5]) //Tiger


enum info {student = '学生', teacher = '教师',  parent = '家长' };

console.log(info.teacher)  //教师

2.4 Any type

any is any type, generally used in obtaining dom
// 任意类型
const newArrs:any = ['测试不同数据 ',222,false]
console.log(newArrs)
# 输出结果为[ '测试不同数据 ', 222, false ]
# 使用场景: 当你不知道类型 或 一个对象 或数据 需要多个类型时,使用any

2.5 undefined type

let num:number | undefined ;
console.log(num) // 输出 undefined, 但是不会报错
let newNum:number | undefined = 33;
console.log(newNum)  // 输出 33 

2.6 never type

never represents a non-existent value type, commonly used as the return type of a function that throws an exception or an infinite loop
# 应用场景 
    #1. 抛错误
    const errDate = (message:string): never => {
        throw new Error(message)
    }
    #2.  死循环
    const date_for = (): never => {
        while(true) {}
    }
    
# never 类型是任意类型的子类型,没有类型是never 的子类型
别的类型不能赋值给never类型, 而 never 类型可以赋值给任意类型

2.7 void type

Void is a function without a type, and is generally used in functions that do not return a value
# 如果方法类型为number, 则必须返回内容, 内容且必须为数字
function add():number{
    return 2323;
}

# 如果方法类型为void,不需要返回内容
function getAdd():void{
    console.log('测试')
}

# 如果方法类型为any,则可以返回任意类型
function getAny():any{
    return 999 + 'Hello TypeScript'
}

console.log(getAny())//999 'Hello TypeScript'

Three, type assertion

What is a type assertion?

  • Sometimes when you define a variable, you don't know what type it is at first, but you know what type it is during use, and then type assertion will be used.
3.1 The first way to write angle brackets
const str = '测试'

const resLength : number = (<string>str).length
3.2 The second way of writing as
const str = '测试'

const resLength : number = (str as string).length

Fourth, the interface

One of the core principles of TypeScript is to type-check structure

When verifying the type, the order does not affect the verification.

Simply put, it is the definition of type constraints. When you use this to define an interface, it will match the types defined in the interface one by one.

As long as it does not satisfy any of the attributes in the interface, it will not pass.

4.1 Interface optional attributes

Sometimes, not all interface attributes are required, but only when certain conditions are met. In this case, optional attributes can be used

Format: Attribute?: Type

interface  Login{
    userName: string,
    password: string,
    auth ?: string
}



function getLogin(obj: Login) {
    if(obj.auth == '管理员') {
        console.log('可以查看所有菜单')
    } else {
        console.log('您的权限比较低,目前不能查看')
    }
}


getLogin({
    userName:'zhangsanfeng',
    password: '12121121sd',
    auth: '管理员'
})    //可以查看所有菜单


getLogin({
    userName:'zhangsanfeng',
    password: '12121121sd'
})    //您的权限比较低,目前不能查看


4.2 Interface read-only attributes

Read-only attribute: It means that after assigning a value to the attribute, it cannot be changed.

Format: readonly attribute: type

interface Menus {
    readonly title?:string,
    icon?:string,
    readonly path?:string,
    readonly Layout?:string
}


function getMenuInfo(data:Menus){
    console.log(data)
    data.icon = '修改图标'   // 可以修改
    // data.path = '/home'    报错,禁止修改,接口属性为只读
    console.log(data)
}


getMenuInfo({
    title: '主页',
    icon:'homes',
    path:'/home',
    Layout: 'Layput'
})
4.3 Interface function types

Used to constrain the function to pass parameter types

  • For the type check of the function type, the parameter name of the function does not need to match the name defined in the interface.
  • Format: (parameter 1: type, parameter 2: type): return value type
// 获取用户信息
interface UserInfo {
    (name: string,adress: string,phone: number) : string
}

let getUsefInfo:UserInfo = function(name,adress,phone){
    return `${name}住在${adress},手机号为${phone}`
}

console.log(getUsefInfo('张锋','天津南开区xx小区',188888888))
4.4 Interface indexable type

When defining an array, you can define an index type interface, which restricts which types of values it must pass.

Access: via variable [index]

interface Code{
    [index : number] : string
}

let errCode : Code = ['200 成功','301 重定向', '400 客户端错误', '500  服务端出错']

console.log(errCode[3])  //500  服务端出错
4.5 Type interface implementation
The interface describes the public part of the class, rather than the public and private parts. It will not help you to check whether the class has certain private members.
interface Animals {
    eye: number,
    leg: number,  
}


class Dog  implements Animals {
    eye: number;
    leg: number;
    kind: string
    constructor(eye: number, leg: number, kind: string) {
        this.eye = eye
        this.leg = leg
        this.kind = kind
    }
    getDogInfo(){
        console.log(`品种为${this.kind},有${this.eye}只眼,${this.leg}条腿`)
    }
}

let hashiqi = new Dog(2,4,'哈士奇');
hashiqi.getDogInfo() //品种为哈士奇,有2只眼,4条腿
4.6 Interface inheritance (all in one)
Interfaces can be inherited from each other, so that interfaces can be divided into reusable modules more flexibly.
interface Shape1 {
    data: string
}

interface Shape2  extends Shape1{
    code: number
    // Shape2 具有 Shape1 的特征
}


class Message implements Shape2 {
    code: number;
    data: string;
    constructor(code : number,data: string) {
        this.code = code;
        this.data = data
    }
    getCodeInfo(){
        console.log(`状态码为${this.code},返回信息为${this.data}`)
    }
}


let err = new Message(500,'服务端错误')
err.getCodeInfo()  //状态码为500,返回信息为服务端错误
4.7 Interface inheritance class

When an interface inherits a class, the interface will also have the attributes and methods of the class.

When other classes implement this interface, they will also implement the properties and methods of the interface, and inherit the properties and methods of the class

class Log {
     time: string = '2020-11-2';
     getLog(){
         console.log('测试')
     }
}

interface  Shape3  extends Log{
    message : string
}



class ErrLog implements Shape3 {
    message: string ;
    time: string;
    constructor(message: string, time: string) {
        this.message = message;
        this.time = time
    }
    getLog(): void {
        console.log("Method not implemented.");
    }
}

let errs = new ErrLog('测试','2020-11-2')
errs.getLog()  //Method not implemented.

Five, generic

Students who have been in contact with JAVA should be familiar with this and are very familiar with it.

As a front-end, we may hear this concept for the first time. It can be seen from the literal meaning that it refers to a wide range of types.

  • Function: to avoid duplication of code, code redundancy

But it is still different from the any type.

  • Any type: If the type of a function is any, then its parameters can be of any type. Generally, the type passed in and the type returned should be the same. If a string type parameter is passed in, then we don't know what type it returns.
  • Generic: It can make the return type of consistent with the incoming type, so that we can clearly know the type returned by the function.
5.1 Generic interface

The generic interface can be understood like this:

When you need to specify a type for an interface, but you don’t know what the attribute type is, you can use a generic interface

You can specify the parameter to the interface as multiple generic types or a single parameter; when using it, you can specify the parameter type.

reJsYR.png

 interface User <T,S,Y> {
     name: T;
     hobby: S;
     age: Y;
 }

 class People implements User<String,String,Number> {
     name: String;
     hobby: String;
     age: Number;
     constructor(name:string,hobby:string,age:number){
         this.name = name;
         this.hobby = hobby;
         this.age = age; 
     }
    getInfo(){
        console.log(this.name+"------------------"+this.hobby)
        console.log(`${this.name}的年龄为${this.age}`)
    }  
 }
 let xiaoZhou =  new People('小周','敲代码',22)
 xiaoZhou.getInfo() 
 //小周------------------敲代码
//  小周的年龄为22
5.2 Generic functions

Defining a generic function can keep the input parameter type consistent with the return value type.

Generic signs are generally capitalized, and T can be changed at will

格式 :  函数名<T> (参数1:T) : 返回值类型 T
function genericity<T> (data: T) : T {
    console.log(data)
    return data
}

genericity("测试")
genericity(666)
genericity(['前端','后端','云端'])

5.3 Generic classes
  1. What is a generic class

It specifies the type of attributes and methods in the class, and must be consistent with the type defined by the type.

  1. The role of generic classes

Can help us confirm that all attributes of the class are using the same type

  1. Use format
class 类名<T> {
 name!: T;
 hobby!: T;
}

# 这样这个类的所有类型为 number
let 实例 =  new 类名<number>();
class GenericityA<X>{
    sex!: X;
    age!: X;
}


let gen = new GenericityA<number>();

// gen.sex = '测试'   报错
gen.age = 3
console.log(gen.age)
5.4 Generic constraints
  1. Interface constraints
  • By defining the interface, the generic function inherits the interface, the parameters must implement the attributes in the interface, so that the constraints of the generic function are reached
  1. Class constraints
  • By assigning the generic type of the class to another class, it is stipulated that the type of the generic type is another class
# 第一种
// 定义接口
 interface DataInfo{
     title: string,
     price: number
 }


//  泛型函数 继承接口,进行对参数类型约束, 如果传入的参数中,没有包含接口属性,则编译不通过
 function getDataInfos< T extends DataInfo> (obj: T) : T {
     return obj
 }

 let book = {
     title: '前端进阶',
     price: 50,  
     author: '小新'
 }

 console.log(getDataInfos(book)) //{ title: '前端进阶', price: 50, author: '小新' }
# 第二种
//  通过类来约束
 class Login{
    username: string;
    password: string;
    constructor(username: string,password:string){
        this.username = username
        this.password = password
    }
 }

class Mysql<T>{
    login<T>(info:T):T{
        return info
    }
}

let  x = new Login('admin','12345');
let  mysql = new Mysql<Login>();
console.log(mysql.login(x)) //Login { username: 'admin', password: '12345' }

<hr/>

Six, Class

Speaking of classes, friends who are back-ends should know that the keyword class class only appeared in ES6 for the front-end.

What are the characteristics of Class

  • Attributes
  • Constructor
  • method
  • Inherit extends
  • Attribute/method modifier
  • Static properties
  • Abstract class
  • getters/setters

6.1 Modifiers

public shared
When the attribute/method modifier is public, if it is not before, it will be added by default, and we can freely access the members defined in the program.
class Fruit {
    public name: string;
    price: number;
    // 以上为等价
    constructor(name: string, price: number) {
        this.name = name;
        this.price = price
    }
    getFruitInfo(){
        console.log(`您要购买的水果为${name},价格为${this.price}`)
    }
}
private private
When a member is marked as private , it cannot be accessed outside the class in which it is declared.
class Fruit {
    public name: string;
    private price: number;

    // 以上为等价
    constructor(name: string, price: number) {
        this.name = name;
        this.price = price
    }
    getFruitInfo(){
        console.log(`您要购买的水果为${name},价格为${this.price}`)
    }
}

const apple = new Fruit('苹果',22)
// console.log(apple.price)   报错, 实例不可以访问私有属性
protected protected
protected modifier and private modifier of behavior is very similar, but a little different, protected members can still access the derived class, property protection can not be accessed by way of example by.
class A {
    protected name : string;
    protected age : number;
    constructor(name: string , age: number) {
        this.name = name;
        this.age = age
    }
    getA(){
        console.log('A')
    }
}

class B extends A {
    protected job : string;
    constructor(name: string, job: string,age: number) {
        super(name,age)
        this.job = job
    }
    getB(){
        console.log(`B 姓名为${this.name} && 年龄为${this.age} && 职业为${this.job},`)
    }
}

let b = new B('小飞','前端工程师',22)
b.getA()  //A
b.getB()   //B 姓名为小飞 && 年龄为22 && 职业为前端工程师,
// console.log(b.name)  报错,访问不了,protected成员只能在派生类中可以访问,不能通过实例来访问。

6.2 Static properties

The static members (attributes and methods) of the class can only be accessed through the class.

Definition: static attribute / static method

class Food {
    public name: string;
    private price: number;
    static adress: string = '四川';
    // 以上为等价
    constructor(name: string, price: number) {
        this.name = name;
        this.price = price
    }
    getFruitInfo(){
        console.log(`您要购买的东西为${name},价格为${this.price}`)
    }
}

const spicy = new Food('辣条',3)

console.log(Food.adress)  //四川
// console.log(spicy.adress)  报错  类的实例对象不可以访问 类的静态属性。 只可以通过类.属性来访问

6.3 Inheritance extend

The intent of inheritance is well understood. When a child class inherits from a parent class, then the child class has the characteristics (attributes) and behaviors (methods) of the parent class.
class T {
    name:string;
    constructor(name:string){
        this.name = name
    }
    getNames(){
        console.log('继承类T')
    }
}

class S extends T {
    constructor(name:string){
        // 派生类拥有T属性和方法
        super(name)
    }
    getName(){
        console.log(this.name)
    }
}

let  ss = new S('测试继承')
ss.getName()  
ss.getNames()
// 测试继承
// 继承类T

6.4 Abstract class

  • Abstract classes can contain the implementation details of members. abstract keyword is used to define abstract classes and define abstract methods inside abstract classes.
  • Abstract methods in abstract classes do not contain concrete implementations and must be implemented in derived classes.
abstract class E{
    abstract name: string;
    abstract speak():void;
    abstract play():void;
}


class F implements E {
    name: string;
    constructor(name:string){
        this.name = name
    }
    //  派生类 F 必须实现 抽象类E 的方法和属性 
    speak(): void {
        console.log('具有聊天功能')
    }
    play(): void {
        console.log('具有娱乐功能')
    }
    get(){
        console.log(this.name)
    }
}


let f = new F('测试');
f.play() //具有娱乐功能
f.get() // 测试
f.speak()  //具有聊天功能

Seven, functions in TS

Function types include parameter types and return value types
7.1 Function add return value type

After adding the type for each parameter, add the return value type for the function itself.

TypeScript can automatically infer the return value type based on the return statement, so we usually omit it.

The following will introduce the format of two writing functions in TS

//  第一种写法
let getInterFaceInfo : (obj:object) => void = function(obj){
    console.log(obj)
}

let infos: object = {
    code: 200,
    message: '发送成功'
}
getInterFaceInfo(infos)


//  第二种写法
function getCode(code: number, message:string) : void {
    console.log(`code为${code},message为${message}`)
}

getCode(200,'接受成功')    
7.2 Function optional parameters / default parameters

In JavaScript, each parameter is optional and can be passed or not. When no parameter is passed, its value is undefined.

In TypeScript, we can use ? beside the parameter name to realize the optional parameter function.

  • Optional parameters must be placed after mandatory parameters.
格式 : 函数名(变量名?:类型):类型 {}  
  • Default parameters, specify default values when passing parameters
格式 : 函数名(变量名 :类型 = "xx"):类型 {}  
//  可选参数
function getNetWork(ip:string,domain:string,agreement?:string){
    console.log(`ip地址为:${ip},域名为${domain},协议为${agreement}`)
}

getNetWork('127.0.0.1','www.xiaomi.com')  //ip地址为:127.0.0.1,域名为www.xiaomi.com,协议为undefined

// 默认参数
function getNetWorks(ip:string,domain:string,agreement:string = 'http'){
    console.log(`ip地址为:${ip},域名为${domain},协议为${agreement}`)
}
getNetWorks('127.0.0.1','www.xiaomi.com') //ip地址为:127.0.0.1,域名为www.xiaomi.com,协议为http    
7.3 Function remaining parameters

Sometimes, you want to manipulate multiple parameters at the same time, or you don't know how many parameters will be passed in.

In JavaScript, you can use arguments to access all incoming parameters.

In TypeScript, all parameters can be concentrated in one variable, preceded by ... indicate the remaining parameters.

Notice

  • Direct access through variables
  • Can also be accessed via index
  • Only one remaining parameter can be defined, and the position is after the default parameter and optional parameter
function getNumberInfo(num:number,...peopleArray: string []) {
    console.log(`人员个数为${num},成员为${peopleArray}`)  // 也可以通过索引来获取元素
    console.log(`人员个数为${num},成员为${peopleArray[1]}`) 
}

getNumberInfo(4,'小明','小李','小红','小张')  
//人员个数为4,成员为小明,小李,小红,小张
//人员个数为4,成员为小李

<hr/>

Eight, enumeration

Enumeration can clearly express a set of corresponding relationships.

TypeScript supports numeric and string-based enumerations.

8.1 Number Enumeration

The default enumeration sequence starts with 0 and then automatically increases.

The enumeration order can also specify the value, after specifying, the first one in front of it still increases by 0

access

  • Enumeration name through . Property access is serial number
  • The attribute name is accessed enumeration name [serial number]
enum Sex {
    x,
    man = 4,
    woman 
}

console.log(Sex.x)   //0
console.log(`小红的性别为${Sex[5]}`) //小红的性别为woman
console.log(`后端接受小红的性别ID ${Sex.woman}`) //后端接受小红的性别ID 5
8.2 String enumeration
enum Job {
    frontEnd = '前端',
    backEnd = '后端'
}

console.log(Job) //{ frontEnd: '前端', backEnd: '后端' }    

Nine, advanced type

9.1 Crossover type
It means that multiple types can be combined into one type. The identifier is & . When a variable type is specified as a cross type, then it has all the attributes of the cross type, that is, the union.
interface DonInterface {
    run():void;
}
interface CatInterface {
    jump():void;
}
//这里的pet将两个类型合并,所以pet必须保护两个类型所定义的方法
let pet : DonInterface & CatInterface = {
    run:function(){},
    jump:function(){}
}
9.2 Union type
  • The union type indicates that a value can be one of several types.
  • Separate each type with a vertical line ( |
  • A value is a union type, and we can only access the members that are common to all types of this union type.
 function getMenus(info: string | number) {
     console.log(info)
 }


getMenus("测试")
getMenus(2)
// getMenus(false)  报错

Ten, modules

Module: Defined variables, functions, classes, etc. can only be used in their own scope. If you want to access it externally, you must use export to export it.

Use the module: Import the content of the import

  • Modules are self-declared; the relationship between two modules is established by using imports and exports at the file level.
  • The module uses the module loader to import other modules. At runtime, the role of the module loader is to find and execute all dependencies of this module before executing the code of this module.

10. Export

10.1 Export declaration

Any declaration (such as variables, functions, classes, type aliases or interfaces) can be export keyword.

export can rename any statement to prevent naming conflicts and modify it through as

# 模块A 文件

// 导出接口
 export interface A {
     getList() : void
 }

//  导出变量
export const  GET_METHOD =  "get"
 

//  导出类
export class S implements A {
    getList(): void {
        console.log("导出类")
    }
    
}

function getQueryData():void {
    console.log("获取分页数据")
}


// 导出模块 变量重命名
export { getQueryData as getQuery}



# 文件B
import {getQuery,S,A} from './模块A';

// 使用模块中的函数
getQuery()

// 实例模块中类的对象
const a = new S();
a.getList()  // 输出导出类

// 实现模块中的 A 接口
class Y implements A {
    getList(): void {
        throw new Error('Method not implemented.');
    }
    
}
10.2 Combination module use

Usually a large module is composed of multiple sub-modules. Then we can import multiple sub-modules in a large module.

Format: export * from "module"

Use combination module: import * as Rename variable from'combination module path'

# 模块C
    //  导出变量
    export const  GET_METHOD =  "get"
# 模块B

export const str: string = "B模块"

export  function getContent():void{
    console.log("我是模块B的内容")
}
#组合模块


 const  res : object =  {
    code: 200,
    message: "请求成功"
 }


export function getRes(): void {
     console.log(res)
 }

 
 # 导出子模块
 export * from "./modulesC"
 export * from "./moduleB"
10.3 Using combination modules
import * as T from "./modulesA";


// C 模块中的
console.log(T.GET_METHOD)


// B 模块中的内容
console.log(T.str)  //B模块
T.getContent() //我是模块B的内容


// A 模块中的内容
T.getRes() //{ code: 200, message: '请求成功' } 
10.4 Default export
Each module can have a default export. The default export is default keyword; and a module can only have one default export.
#模块

export interface K {
    name:string;
    birth:string;
}


export default class Student implements K {
    name: string;
    birth: string;
    constructor(name:string,birth:string){
        this.name = name;
        this.birth = birth;
    } 
    getStudentInfo(){
        console.log(this.name+this.birth)
    }
}
#文件A
import D,{K} from './modulesD'


//  使用默认导出
 const d = new D('小明','1998')
 d.getStudentInfo()


// 参数类型为接口K 
 function getMessage(obj: K): void {
    console.log(obj)
 }
 let obj = {
     name:"小红",
     birth: "1998"
 }
 getMessage(obj);

10.5 export = and import = require()

exports variable in CommonJS and AMD environment, this variable contains all the exported content of a module.

Both CommonJS and AMD's exports can be assigned to a object

exports have the same purpose as export default not compatible with CommonJS and AMD’s exports .

In TypeScript, in order to achieve this effect, you can write:

Derived: export = is equal to exports

Import: import module = require("module")

# 模块
// 相当于默认导出
export = class Mongodbs{
    host:string;
    user:string;
    password:string;
    port:number;
    databaseName:string;
    constructor(host:string,user:string,password:string,port:number,databaseName:string) {
        this.host = host;
        this.user = user;
        this.password = password;
        this.port = port;
        this.databaseName = databaseName
    }
    query(table:string){
        console.log(`select * from ${table}`)
    }
}
#使用模块

import MogoDb = require("./modulesE")  

const mogodb = new MogoDb('1270.0.1','admin','123456',3006,'TypeScript')

mogodb.query('Vue') //select * from Vue

Eleven, namespace

  1. definition
  • "Internal modules" are called "namespaces"
  • "External modules" are called "modules"
  1. effect
  • Reduce naming conflicts and organize code into a space for easy access.
  1. Use format
  • Use namespace space name {}, internally export through 06128635024612 to use internal members
namespace XiaoXin {
    export interface  GetData{
        name: string;
        price: number;
        getInfo(obj:object):any;
    }
    export interface  GetMessage {
        code: number;
        message: string;
    }

    export class Book implements  GetData{
        name: string;
        price: number;
        constructor(name:string,price:number){
            this.name = name;
            this.price = price
        }
        getInfo(obj: object) {
            throw new Error("Method not implemented.");
        }
        buyBook(obj: GetMessage) {
            console.log(obj)
        }
    }           
}


const fontEnd = new  XiaoXin.Book("前端开发手册",99)

var obj = {
    code: 200,
    message:"购买成功"
}

fontEnd.buyBook(obj)  //{ code: 200, message: '购买成功' }


function test(obj:XiaoXin.GetMessage){
    console.log(obj)
}

test(obj)  //{ code: 200, message: '购买成功' }    

11.1 Split Namespace

When the application becomes larger and larger, we need to separate the code into different files for easy maintenance.

We can split the namespace file into multiple files, but they still use the same namespace name, and each file depends on each other. But the namespace file must be introduced at the beginning of the file.

Format: /// <reference path="MS1.ts"/>

# 根命名空间
namespace School {
    export const schoolName =  "清华大学"
}
# 子命名空间1
/// <reference path="MS1.ts" />

namespace School{
    export class Teacher {
        faculty:string;
        name:string;
        age:number;
        constructor(faculty:string,name:string,age:number){
            this.faculty = faculty;
            this.name = name;
            this.age = age
        }
        getInfo(){
            console.log(`${this.name}为${this.faculty},年龄为${this.age}`)
        }
        getSchool(schoole:string){
            console.log(`${this.name}老师就职于${schoole}`)
        }
    }
}
#  子命名空间2
///  <reference path="MS1.ts" />

 namespace School{
     export class Student{
         name:string;
         age:number;
         hobby:string;
         constructor(name:string,age:number,hobby:string) {
             this.name = name;
             this.age = age;
             this.hobby = hobby;
         }
         getInfo(){
             console.log(`${this.name}是一个学生,年龄为${this.age},爱好是${this.hobby}`)
         }
     }
 }
# 使用合并的命名空间


导入命名空间
/// <reference path="MS1.ts" />
/// <reference path="MS2.ts" />
/// <reference path="MS4.ts" />



let teacher = new School.Teacher('计算机教授','张博士',34);
teacher.getInfo() //张博士为计算机教授,年龄为34
teacher.getSchool(School.schoolName)  //张博士老师就职于清华大学


let students = new School.Student('张三',17,'玩LOL');
students.getInfo()  //张三是一个学生,年龄为17,爱好是玩LOL

Compile the namespace file
第一种方法: 会编译为 一个js文件
tsc --outFile sample.js Test.ts


第二种方法:  会编译为多个js文件,然后通过 <script> src 引入js文件即可
tsc --outFile sample.js Validation.ts LettersOnlyValidator.ts ZipCodeValidator.ts Test.ts

12. Decorator

Decorator is a special type of declaration that can be attached to class declarations, methods, accessors, attributes, and parameters of class methods to achieve the behavior of extending classes.

Since ES2015 introduced class , when we need to share or extend some methods or behaviors between multiple different classes, the code will become intricate and extremely inelegant. This is also a very important reason why decorators are proposed.

12.1 Classification of decorators
  • Class decorator
  • Attribute decorator
  • Method decorator
  • Parameter decorator
修饰器写法: 1. 普通修饰器  (不传参数)
           2.  装饰器工厂 (传参数)
12.2 Class decorators

The class decorator expression will be called as a function at runtime, with the constructor of the class as its only parameter.

Usage scenario: Applied to the class constructor, it can be used to monitor, modify or replace the class definition.

const extension = (constructor: Function):any => {
    constructor.prototype.coreHour = '10:00-15:00'
  
    constructor.prototype.meeting = () => {
      console.log('重载:Daily meeting!');
    }

  }

@extension
class Employee {
  public name!: string
  public department!: string


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

  meeting() {
    console.log('Every Monday!')
  }

}

let e: any = new Employee('装饰器', '测试')
console.log(e)  //Employee { name: '装饰器', department: '测试' }
 console.log(e.coreHour) // 10:00-15:00
 e.meeting()             // 重载:Daily meeting!
  
12.3 Class attribute decorator

The decorator expression acting on the class attribute will be called as a function at runtime, passing in the following three parameters target , name , descriptor :

  • target : For static members, it is the constructor of the class, and for instance members, it is the prototype object of the class
  • name : Member's name
  • descriptor : The attribute descriptor of the member

Execution order: When calling a function with a decorator, the decorator will be executed first, and then the function will be executed.

To complete an attribute read-only function through the decorator is actually to modify the value writable

function readonly(value: boolean){
    return function(target:any,name:string,descriptor:PropertyDescriptor) {
        descriptor.writable = value
    }
}


class Student{
    name:string;
    school:string = '社会大学'
    constructor(name:string) {
        this.name = name
    }
    @readonly(false)
    getDataInfo(){
        console.log(`${this.name}毕业于${this.school}`)
    }
}

let sss = new Student('小李子')
// 报错,  只能读,不能修改
// sss.getDataInfo = () => {
//     console.log("测试修改")
// }

sss.getDataInfo()

Previous wonderful articles

finally

If you like it, you can like it 👍👍👍Follow and support, I hope everyone can gain something after reading this article!

Welcome to pay attention to the public number: Front-end self-study community


程序员海军
981 声望7k 粉丝