TypeScript学习笔记

TypeScript

一、TypeScript 介绍

  1. TypeScript 是由微软开发的一款开源的编程语言
  2. TypeScript 是 JavaScript的超集,遵循最新的ES6、ES5规范。TypeScript扩展了JavaScript的语法
  3. TypeScript 更像后端Java、C#这样的面向对象语言。可以让JavaScript开发大型企业项目
  4. 谷歌也在大力支持TypeScript的推广,谷歌的 angular 2.x+就是基于TypeScript语法
  5. 最新的Vue、React 也可以集成TypeScript
  6. NodeJS 框架 Nestjs、midway 中用的就是TypeScript语法

TypeScript包含JavaScript

二、TypeScript 安装、编译

在使用npm 命令之前电脑必须安装nodejs

2.1、安装

npm install -g typescript

//查看版本、验证是否安装完成
tsc -v

2.2、运行

将 TS 文件编译为 JS文件

//终端进入目标文件所在文件夹
//执行:tsc 文件名.ts
//tsc .\01-index.ts
tsc greeter.ts
2.2.1、自动编译

1

//在目标目录执行
tsc --init
//生成tsconfig.json配置文件
//将下面代码注释取消掉
 "outDir": "./",                              /* 将输出结构重定向到目录. */
//可指定输出js文件所在文件夹
//如:"outDir": "./js",

VScode编辑器中,点击 终端 ==> 运行任务 ==> typescript ==> tsc : 监视 ‘xxxxxxxx’

随后保存文件时就会自动编译ts文件

三、TypeScript中的数据类型

typescript中为了使编写的代码更规范,更利于维护,增加了类型校验,在typescript中主要提供了以下数据类型

  • 布尔类型(boolean)
  • 数字类型(number)
  • 字符串类型(string)
  • 数组类型(array)
  • 元组类型(tuple)
  • 枚举类型(enum)
  • 任意类型(any)
  • null和undefined
  • void类型
  • never类型

typescript中声明变量时要声明类型

3.1、布尔类型

//布尔类型只能说true或false
let a:boolean = true 
//如果赋值不是对应数据类型,编译将不通过

3.2、数字类型

let b:number = 123
b = 12.3

3.3、字符串类型

let str:string = 'im string'
// 赋值类型不相符时会报错
// str = 123
// str = true

3.4、数组类型

1、使用 变量名:类型[] 定义数组

// 指定数组为数字数组
let arr:number[] = [123,34,21,2]
// 当包含其他数据类型时会报错
// arr = [1,2,3,'a']
// 其他类型同理
let arr1:string[] = ['a','d','c']
let arr2:any[] = ['a',123,{name:'sd'}]

2、使用 变量名:Array<数组中的数据类型> 泛型定义数组

Vue中是否支持泛型?

let arr2:Array<number> = [1,2,3,4]

3.5、元组类型

属于数组的一种

//后方赋值必须和定义的数组长度、类型位置一致
//否则将会报错
let arr3:[string,number,boolean] = ['a',23,true]

3.6、枚举类型

随着计算机的不断普及,程序不仅只用于数值计算,还更广泛地用于处理非数值的数据。例如:性别、月份、星期几、颜色、单位名、学历、职业等,都不是数值数据。
在其它程序设计语言中,一般用一个数值来代表某一状态,这种处理方法不直观,易读性差。如果能在程序中用自然语言中有相应含义的单词来代表某一状态,则程序就很容易阅读和理解。
也就是说,事先考虑到某一变量可能取的值,尽量用自然语言中含义清楚的单词来表示它的每一个值,这种方法称为枚举方法,用这种方法定义的类型称枚举类型。

简单理解为:使用不同数值表示不同的状态

// enum 枚举名 {
//   标识符[=整型常数]
//   标识符[=整型常数]
//	 ...
//   标识符[=整型常数]
//   标识符[=整型常数]
// }
#枚举名首字母大写
enum Flag {
  success = 1,
  error = -1
}

let ok:Flag = Flag.success

console.log(ok,Flag.error)
//当没有给标识符指定常数时,将会返回其下标
enum Color {
  red,
  blue,
  yellow
}
let c:Color = Color.red
console.log(c)

enum Color {
  red,
  blue=5,
  yellow
}
let c:Color = Color.red
//打印Color.red		0
//打印Color.blue		5
//打印Color.yellow	6	//当前标识符没有赋值,但前方标识符有值时,其值会紧接前方标识符的值 +1
console.log(c)

3.7、任意类型

// ========= 任意类型
// 允许变量为任何类型
let aaa:any = 'asd'
aaa = 123

3.8、null和undefined

let t3:null
// t3='as'    //报错


let t1:undefined
console.log(t1)     //undefined     不会报错

// let t2:number
// console.log(t2)     //undefined     报错

3.9、void类型

typescript中的void表示没有任何类型,一般用于定义方法的时候 方法没有返回值

// 表示方法没有返回值
let fn11 = ():void => {
  console.log('fn11')
}
fn11()

// 指定返回值类型为number
let fn12 = ():number => {
  console.log('fn11')
  return 123
}
fn12()

// 不指定(原本js写法
let fn13 = () => {
  console.log('fn11')
  return 123
}
fn13()

3.10、never类型

是其他类型(包括null和undefined)的子类型,代表从不会出现的值

这意味着设声明never的变量只能被never类型所赋值

使用较少

let a:never

a = (() => {
    throw new Error('错误')
})

3.11、允许变量多个类型

// 指定多种数据类型
//允许变量为	数字	undefined	null
let bbb:number | undefined | null

bbb = 123

// bbb = 'ass'

四、TypeScript中的函数

4.1、函数的使用

//  ========== es5中定义函数
// 具名函数
function run() {
  return 'run'
}
// 匿名函数
let run2 = () => {
  return 'run2'
}

//  ======== ts中定义函数
// 具名函数
function run3():string{
  return 'str'
}
// 匿名函数
let run4 = ():number => {
  return 123
}

console.log(run3(),run4())

4.2、函数传参

定义参数类型和返回值类型

let getName = (name:string,age:number):string => {
  return `${name}-----${age}`
}
// console.log(getName('asd','20'))    //报错,参数类型必须符合定义规范
console.log(getName('asd',20))

// 没有返回值的方法
let noBack = (name:string):void => {
  console.log(name)
}

4.3、可选参数

在变量名后加 ? 表示该参数可传,可不传

let getName2 = (name:string,age?:number):string => {
  if(age){
    return `${name}-----${age}`
  }else{
    return `${name}-----未传年龄`
  }
}
console.log(getName2('asd',20))
console.log(getName2('asd'))

4.4、设置默认参数

es5中不能设置默认参数,es6和ts中可设置默认参数

在指定类型后加 =默认值 ,设置默认参数

let getName3 = (name:string,age:number=20):string => {
  return `${name}-----${age}`
}
console.log(getName3('asd'))
console.log(getName3('asd',13))

4.5、剩余参数

结合ES6中的扩展运算符 …

let sumFn = (...intNum:number[]):number => {
  let sum = 0
  intNum.forEach((item) => {
    sum += item
  })
  return sum
}
console.log(sumFn(1,2,3,4,5))

4.6、函数重载

Java中的方法重载,重载指的是两个或两个以上的同名函数,但他们的参数不一样,这时会出现函数重载的情况
typescript中的重载,通过为同一个函数提供多个函数类型定义来实现多种功能的目的

// ES5中,下方函数会替换上方同名函数

// function infor(name){
// }
// function infor(age){
// }

// ts中的重载
function infor(name:string):string
function infor(age:number):number

function infor(arg:any):any{
  if(typeof str === 'string'){
    return '姓名' + arg
  }else{
    return  '年龄' + arg
  }
}
console.log(infor('nb'))
console.log(infor(23))
// console.log(infor(true))  //错误用法

#暂时没有理解重载优势

五、类

5.1、ES5\ES6中定义类

#===========  ES5中定义类
function Person(name){
  this.name = name;
  this.say = function() {
    console.log(this.name)
  }
}

let p1 = new Person('张三')
p1.say()

#===========  ES6中的定义类
class Student{
  constructor(name,age){
    this.name = name;
    this.age = age
  }
  say(){
    console.log(this.name + '--------' + this.age)
  }
}
let stu1 = new Student('张三',12)
stu1.say()

5.2、ts中定义类

class Teacher{
  // 先定义类中属性的类型
  name:string;
  age:number
  constructor(n:string,age:number=20){
    // this.name:string = n     //这样定义类型会报错
    this.name = n;
    this.age = age;
  }
  say():void{
    console.log(this.name + 'hi' + this.age)
  }
  getName():string{
    return this.name
  }
  setName(newName:string):void{
    this.name = newName
  }
}
let teacher1 = new Teacher('小丽')

teacher1.say()
teacher1.getName()
teacher1.setName('小丽丽')
teacher1.say()

5.3、继承 extends

class Boy{
  name:string;
  age:number;
  constructor(n:string,a:number){
    this.name = n;
    this.age = a
  }
  run():void{
    console.log(this.name + 'is running')
  }
}
let b1 = new Boy('小王',22)
console.log(b1)
b1.run()
// 使 Girl  继承  Boy
class Girl extends Boy{

}

let g1 = new Girl('小芳',18)
console.log(g1)
g1.run()

5.4、super关键字

// 使用 super 继承  Boy 的构造函数
// super关键字能将构造函数继承后指向 新类(Kid) 而非 原类(Boy)
class Kid extends Boy {
  constructor(n:string,a:number){
    super(n,a)
  }
  // 子类和父类中有相同的方法时,会调用子类的方法(就近原则
  run():void{
    console.log(this.name + '在游泳')
  }
  // 子类新增方法
  play():void{
    console.log(this.name + '在打游戏')
  }
}
let k1 = new Kid('小弟弟',9)
console.log(k1)
k1.run()
k1.play()

5.5、TS类中的修饰符

typescript里面定义属性的时候给我们提供了三种修饰符

1 public:公有类型(默认类型) 在当前类、子类、类外面都可以访问
2 protected:保护类型 在当前类、子类可以访问,在类外部无法访问
3 private:私有类型 在当前类中可以访问,子类和类外部都无法访问

#  === 父类
class Father{
  // 设置为public
  public name:string;
  protected age:number;
  private money:number

  constructor(n:string,a:number,m:number){
    this.name = n;
    this.age = a;
    this.money = m
  }
  sayName():void{
    console.log(`姓名:${this.name}`)
  }
  sayAge():void{
    console.log(`年龄:${this.age}`)
  }
  showMoney():void{
    console.log(`现金:${this.money}`)
  }
}
let f1 = new Father('父类',37,900000)
console.log({msg:'父类中访问属性'})
// 访问 public 属性
f1.sayName()
// 访问 protected 属性
f1.sayAge()
// 访问 private 属性
f1.showMoney()

#	=== 子类
class Son extends Father {
  constructor(n:string,a:number,m:number){
    super(n,a,m)
  }
  sonSayName():void{
    console.log(`姓名:${this.name}`)
  }
  sonSayAge():void{
    console.log(`年龄:${this.age}`)
  }
  sonShowMoney():void{
    // console.log(`现金:${this.money}`)     //子类不能访问父类私有属性,编译报错
  }
}
let s1  = new Son('小兰兰',10,200)
console.log({msg:'子类中访问属性'})
// 访问 public 属性
s1.sonSayName()
// 访问 protected 属性
s1.sonSayAge()
// 访问 private 属性
s1.sonShowMoney()


#  类外部访问
console.log({msg:'类外部访问属性'})
// 访问 public 属性
console.log(f1.name)
// 访问 protected 属性
// console.log(f1.age)        //外部不能访问父类保护属性,语法错误,编译报错
// 访问 private 属性
// console.log(f1.money)      //外部不能访问父类私有属性,语法错误,编译报错

5.6、TS静态方法/属性

# ES5function Personfour(){
  this.run = function(){
    console.log('实例方法')
  }
}

Personfour.say = function(){
  console.log('静态方法')
}

// 实例方法需要 new 实例化对象后才能使用
let p4 = new Personfour()
p4.run()

// 静态方法不需要实例化即可调用
Personfour.say()
#	TS中
class Student{
  public name:string;
  public money:number = 0
  // 使用 static  定义静态属性
  static sex:string = '女'
  constructor(name:string){
    this.name = name
  }
  // 实例方法
  doThing():void{
    console.log(`${this.name} is sleeping`)
  }
  // 使用 static  关键字设置静态方法
  // 静态方法中,不能直接调用类里面的属性
  static work():void{
    console.log('静态方法')
    // console.log(`${this.name} have ${this.money}`)
    // 静态方法中可以访问静态属性
    console.log(`sex is ${this.sex}`)
  }
}
let stu = new Student('小恐龙')
stu.doThing()
// 访问静态方法
Student.work()
// 访问静态属性
console.log(Student.sex)

5.7、TS多态

父类定义一个方法不去实现,让继承他爱的子类去实现,每一个子类有不同的表现
多态属于继承

class Aniaml {
  name:string;
  constructor(name:string){
    this.name = name
  }
  
  eat(){
    console.log(`吃东西`)
  }
}

class Dog extends Aniaml {
  constructor(name:string){
    super(name)
  }
  
  eat():string{
    console.log(`吃东西`)
    return this.name + '吃骨头'
  }
}

class Cat extends Aniaml {
  constructor(name:string){
    super(name)
  }
  
  eat():void{
    console.log(`吃东西`)
    console.log(this.name + '吃老鼠')
  }
}

5.8、抽象类

抽象类用来定义标准

其是提供其他类继承的基类,不能直接被实例化

使用 abstract 关键字定义抽象类和抽象方法,抽象类中的抽象方法不包含具体实现,并且必须在派生类中实现

abstract 抽象方法只能放在抽象类中 !

抽象类中的抽象方法用来定义标准 !

如: Animals 类的子类必须包含eat方法

//定义抽象类
abstract class Animals{
  public name:string;
  constructor(name:string){
    this.name = name
  }
  sleep():void{
    console.log(this.name + 'is sleeping')
  }
  // 定义抽象方法
  abstract eat():any
}

// let aaa = new Animals()    //抽象类不能被实例化

class Fish extends Animals{
  constructor(name:string){
    super(name)
  }
  // 抽象对象的子类/派生类中必须实现抽象方法
  eat():void{
    console.log(this.name + '吃鱼')
  }
}
let f = new Fish('鲸鱼')
f.eat()

六、接口

接口的作用,在面向对象的编程中,接口是一种规范的定义。它定义了行为和动作的规范,在程序设计里面,接口起到了一种限制和规范的作用。

接口定义了某一批类所需要遵守的规范,接口不关心这些类的内部状态数据,也不关心这些类里方法的实现细节。

它只规定这些类里必须提供某些方法,提供这些方法的类就可以满足实际需要。

TypeScript中的接口类似于Java,同时还增加了更灵活的接口类型,包括属性、函数、可索引和类等

简单理解:对传入的参数进行类型约束,定义标准

6.1、使用

// ts中定义方法
function showLabel(label:string):void{
  console.log('showLabel'+label)
}
showLabel('lll')


// 1.属性接口 
// 对某一个属性进行约束
function printfLabel(label:string):void{
  console.log('printfLabel' + label)
}  
// 对对象属性进行约束
function showInfor(fooInfor:{foo:string}):void{
  console.log(fooInfor)
}
showInfor({foo:'heiheihei'})

6.2、使用interface定义接口对象

interface FullName{
  firstName:string;   //注意:这里为 ;
  secondName:string
}

function printName(name:FullName){
  console.log(name)
  // console.log(name.firstName +'--' +name.secondName,name.age)    //不能使用interface中没有规定的属性
}
printName({
  firstName:'da',
  secondName:'opp',
})
// 赋值传入时,只能包含 interface 约束中的属性
// printName({
//   firstName:'小',
//   secondName:'厘子',
//   age:20
// })
let aa = {
  firstName:'小', 
  secondName:'厘子', 
  age:20
}
// 直接传入对象,只要对象中满足条件就可以
printName(aa)


#	使用 ? 设置可选属性
interface Boy{
  name:string;
  age?:number;
}
function showBoy(infor:Boy):void{
  console.log(infor)
}
showBoy({
  name:'小张'
})

6.3、例子:封装简易ajax

// 定义接口约束
interface Config{
  type:string;
  url:string;
  data?:string;
  dataType:string
}

function ajaxFn(config:Config){
  const xhr = new XMLHttpRequest()
  // open的第三个参数表示是否为异步操作
  xhr.open(config.type,config.url,true)
  xhr.send(config.data)
  xhr.onreadystatechange = () => {
    if(xhr.readyState === 4 && xhr.status == 200){
      console.log('OK')
      console.log(xhr.response,xhr.responseType == config.type)
    }
  }
}

ajaxFn({
  type:'get',
  url:'http://www.2twl.com/api/getnewslength',
  dataType:'json',
  data:''
})

6.4、函数类型接口

对方法传入的参数,以及返回值进行约束

// 例子:加密的函数类型接口
 interface yuesu{
  //  (参数:类型):返回值类型
   (key:string,value:string):string
 }

 let mymd5:yuesu = function(key:string,value:string):string{
  //  模拟返回值
  return key + value
 }

 console.log(mymd5('zzz','qqq'))

6.5、可索引接口

通常对对象、数组的约束(不常用

// 对数组约束
interface Myarr{
  // 索引:数组中的数据类型
  [index:number]:string
}
let newarr:Myarr=['ac','dc']
console.log(newarr[0])

// 对对象约束
interface Myobj{
  [index:string]:string
}

let zs:Myobj = {
  name:'zhangsan',
  // age:12    //局限性强
}

6.6、类类型接口

对类的约束 和抽象类类似(约束/标准中的属性和方法必须实现)

interface MyAnimal{
  name:string;
  eat(str:string):void
}

// 让 Mydog 类实现 myanimal 接口
class MyDog implements MyAnimal{
  name:string;
  constructor(name:string){
    this.name = name
  }
  eat(food:string):void{
    console.log(this.name + ' is eating ' + food)
  }
}

let dd1 = new MyDog('opp')
dd1.eat('fish')

6.7、接口扩展

// 接口可以继承接口
interface Aanimal{
  eat():void
}
// Aperson 类接口 继承  Aanimal 类接口
interface Aperson extends Aanimal{
  work():void
}

class WebMan implements Aperson{
  name:string;
  constructor(name:string){
    this.name = name
  }
  eat(){
    console.log(this.name + ' eat food')
  }
  work(){
    console.log(this.name + ' is working')
  }
}

let xw = new WebMan('小王')
xw.eat()
xw.work()

6.8、继承类并实现指定接口

// 定义一个类
class WorkMan{
  name:string;
  constructor(name:string){
    this.name = name
  }
  code():void{
    console.log(this.name + ' is coding')
  }
}
// 使新类 NewWebMan 继承旧类 WorkMan ,并且实现 Aperson 接口
class NewWebMan extends WorkMan implements Aperson{
  constructor(name:string){
    super(name)
  }
  eat(){
    console.log(this.name + 'is NewWebMan,eat')
  }
  work(){
    console.log(this.name + 'is NewWebMan,work')
  }
}
let nn = new NewWebMan('牛牛')
nn.eat()
nn.work()
nn.code()

七、泛型

泛型:软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可复用性。

组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时提供十分灵活的功能

在像C#和Java这样的语言中,可以使用泛型来创建和复用的组件,一个组件可以支持多种类型的数据。

这样用户就可以以自己的数据类型来使用组件

通俗理解:泛型就是解决、类、接口、方法的复用性,以及对非特定数据类型的支持

泛型:可以支持不特定的数据类型

7.1、初步使用

// 1、要求:传入和返回的数据类型一致

// T表示泛型,具体什么类型由调用的时候决定
function getData<T>(value:T):T{
  return  value
}

// 使用
getData<number>(123)
// getData<number>('asd')    //错误用法

// 2、要求:传入和返回的数据类型不一致
function fn1<T>(value:T):any{
  return '123'
}

// 使用
getData<number>(123)

7.2、泛型类

// 最小堆算法,需要同时支持返回数字和字符串两种类型,通过类的泛型来实现

#	不使用泛型
class MinClass{
  public list:number[] =[];
  constructor(){

  }
  add(num:number){
    this.list.push(num)
  }
  min():number{
    // let minNum = Math.min(...this.list)
    // return minNum

    let minNum = this.list[0]
    this.list.forEach((item,index) => {
      if(minNum > item){
        minNum = item
      }
    })
    return minNum
  }
}


#	使用泛型
class MinList<T>{
  public arr:T[] = []
  add(num:T){
    this.arr.push(num)
  }
  min():T{
    let minNum = this.arr[0]
    this.arr.forEach((item,index) => {
      if(minNum > item){
        minNum = item
      }
    })
    return minNum
  }
}

//  实例化泛型类,并指定数据类型
let a1 = new MinList<number>()
a1.add(1)
a1.add(5)
a1.add(4)
a1.add(2)
a1.add(0)
console.log(a1.min())

//  实例化泛型类,并指定数据类型
let a2 = new MinList<string>()
a2.add('a')
a2.add('d')
a2.add('t')
a2.add('h')
a2.add('d')
console.log(a2.min())

7.3、泛型接口

// 1-第一种方法
// 普通函数接口
interface ConfigFn{
  (value1:string,value2:string):string
}

let setData:ConfigFn = (value1:string,value2:string):string => {
  return value1 + value2
}

// 泛型函数接口
interface ConfigFn2{
  <T>(value:T):T
}
let getData2:ConfigFn2 = <T>(value:T):T => {
  console.log(value)
  return value
}
getData2<string>('sad')

// 2-第二种方法
interface ConfigFn3<T>{
  (value:T):T
}

let getFn3 = <T>(value:T):T => {
  return value
}
let myFn3:ConfigFn3<string> = getFn3

myFn3('asd')

八、接口、泛型综合使用

约束规范使用定义接口,代码复用使用泛型

// 1-普通接口
// interface Dbi{
//   add():boolean;
//   get():any[];
//   updata():boolean;
//   delete():boolean
// }
// 2-增加泛型
interface DBI<T>{
  add(data:T):boolean;
  get(id:number):any[];
  updata(data:T,id:number):boolean;
  delete(id:number):boolean
}

// 3-定义一个操作mysql数据库的类
// 注意:要实现泛型接口,这个类也应该是一个泛型类
class MysqlDB<T> implements DBI<T>{
  constructor(){
    console.log('连接数据库,在构造函数中进行连接')
  }
  add(data: T): boolean {
    console.log(data)
    return true
    // throw new Error("Method not implemented.");
  }
  get(id: number): any[] {
    throw new Error("Method not implemented.");
  }
  updata(data: T, id: number): boolean {
    throw new Error("Method not implemented.");
  }
  delete(id: number): boolean {
    throw new Error("Method not implemented.");
  }
}
// myssl
class MysslDB<T> implements DBI<T>{
	... 
}
// 4-定义一个User类
class User{
  username:string | undefined;
  password:string | undefined;
}

let u = new User()
u.username = 'bob111'
u.password = '12345'

// 可以将类传入<>中作为约束条件
let oMysql = new MysqlDB<User>()

oMysql.add(u)


#	理解:以上方法可以轻松切换操作不同数据库(前提均已连接数据库)

九、模块

9.1、概念

模块的的概念(官方):
  关于术语的一点说明:请务必注意一点,TypeScript 1.5里术语名已经发生了变化。“内部模块*现在称做"命名空间”。
  “外部模块”现在则简称为“模块”模块在其自身的作用域里执行,而不是在全局作用域里;
  这意味着定义在一个模块里的变量,函数,类等等在模块外部是不可见的,除非你明确地使用export形式之一导出它们。
  相反,如果想使用其它模块导出的变量,函数,类,接口等的时候,你必须要导入它们,可以使用import形式之一。

模块的概念(通俗理解):
  我们可以把一些公共的功能单独抽离成一个文件作为一个模块。、
  模块里面的变量函数类等默认是私有的,如果我们要在外部访问模块里面的数据(变量、函敞、类),
  我们需要通过export暴露模块里面的数据(变量、函数、类...)。
  暴露后我们通过import 引入模块就可以使用模块里面暴露的数据(变量、函数、类...)。

9.2、导出和引入

#// 导出
// 1、直接导出
export function aFn():void{
  console.log('aFn')
}
let a = 'asd'
function bFn():void{
  console.log('aFn')
}
// 2、统一导出
export {
  a,bFn
}

// 3、export default
// 默认导出,每个模块中只能使用一次


#// 引入
//1、普通引入
// import { aFn,bFn } from "./08-mokuai" 

// 2、别名引入
// import { aFn as a } from "./08-mokuai"

注意:编译之后会由ES6规范 变为 CommonJS规范,须在nodeJS环境下运行
可通过webpack等工具配置后在浏览器运行

十、命名空间

10.1、概念

命名空间:

在代码量较大的情况下,为了避免各种变量名相冲突,可将相似功能的函数、类、接口等放置到命名空间内

同Java的包,.net的命名空间一样,TypeScript的命名空间可以将代码包裹起来,只对外暴露要在外部访问的对象。

命名空间内的对象通过export导出

命名空间和模块的区别:

命名空间:内部模块,注意用于组织代码,避免命名冲突

模块:ts的外部模块的简称,侧重于代码的复用,一个模块里可能有多个命名空间

10.2、使用

// 定义命名空间A
// 命名空间中的方法默认为私有,想在外部使用需先export暴露
namespace A {
  interface Animal{
    name:string;
    eat():void
  }
  class Dog implements Aanimal{
    name:string;
    constructor(name:string){
      this.name = name
    }
    eat():void{
      console.log(this.name + ' eat food')
    }
  }
  export class Cat implements Aanimal{
    name:string;
    constructor(name:string){
      this.name = name
    }
    eat():void{
      console.log(this.name + ' eat fish')
    }
  }
}

// 使用   命名空间名.暴露属性名 进行访问
let c1 = new A.Cat('小花猫')
c1.eat()

// 命名空间B
namespace B {
  interface Animal{
    name:string;
    eat():void
  }
  class Dog implements Aanimal{
    name:string;
    constructor(name:string){
      this.name = name
    }
    eat():void{
      console.log(this.name + ' eat food')
    }
  }
  export class Cat implements Aanimal{
    name:string;
    constructor(name:string){
      this.name = name
    }
    eat():void{
      console.log(this.name + ' eat fish')
    }
  }
}

let c2 = new B.Cat('小花猫B')
c2.eat()

10.3、暴露命名空间

// 暴露命名空间C
export namespace C{

}

十一、装饰器

11.1、概念

# 不太理解实际使用,需后续学习

装饰器:装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,属性或参数上,可以修改类的行为。

通俗的讲装饰器就是一个方法,可以注入到类、方法、属性参数上来扩展类、属性、方法、参数的功能。

常见的装饰器有:类装饰器、属性装饰器、方法装饰器、参数装饰器

装饰器的写法:普通装饰器(无法传参)、装饰器工厂(可传参)

装饰器是过去几年中js最大的成就之一,已是Es7的标准特性之一

11.2、类装饰器

类装饰器在声明之前被声明(紧靠着类声明)。类装饰器应用于类构造函数,可以用来监视、修改或替换类定义

传入一个参数

#	普通装饰器(没有参数
// 1、声明装饰器
function zsFn(params:any){
  console.log(params)
  // params就是使用装饰器的当前类

  // 在不修改类的前提下,扩展属性和方法
  // 给当前类扩展属性
  params.prototype.sex = '女'
  //方法 
  params.prototype.sleep = () => {
    console.log('sleep')
  }
}


// 2、定义类,通过@使用装饰器
@zsFn
class Person{
  constructor(){
  }
  eat(){
    
  }
}

let p1 = new Person()
console.log(p1)

#	 装饰器工厂(可传参
function zsqGC(params:string){

  // return 函数中的参数为当前类
  return function(target:any){
    console.log(target,params)
    target.prototype.addType = params
  }
}


@zsqGC('修饰工厂')
class Tea{
  fn(){
    console.log('need water')
  }
}

let tea1 = new Tea()
console.log(tea1)

11.3、属性修饰器

// 类修饰器
function ObjFn(params:string){
  return function (target:any){
    console.log(target,'类修饰器')
    target.prototype.addNew = params
  }
}

// 属性修饰器
function AttrFn(params:string){
  return function(target:any,attr:any){
    console.log(target,attr,'属性修饰器')
    target[attr] = params
  }
}

@ObjFn('olo')
class TestObj{
  @AttrFn('llllllllll')
  name:string | undefined;
  constructor(){
    this.name = 'deeeeee'
  }
  getName(){
    console.log(this.name)
  }
}

let t2 = new TestObj()

console.log(t2)

11.4、方法装饰器

它会被应用到方法的属性描述符上,可以用来监视,修改或者替换方法定义。

方法装饰会在运行时传入下列3个参数:

1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。

2、成员的名字。

3、成员的属性描述符。

// 修饰器
function Fn3(params:string){
  return function(target:any,methodName:any,desc:any){
    console.log(target,'方法装饰器')
    console.log(methodName,'方法装饰器')
    console.log(desc,'方法装饰器')
    target.name  = 'okk'
    target.run = () => {
      console.log('run!!!')
    }
  }
}

// 类
class MethodFn{
  public name:string | undefined
  constructor(){

  }
  // 使用修饰器
  @Fn3('www.sex.bb')
  getData(){
    console.log(this.name)
  }
  eat(){
    console.log(this.name + 'eat')
  }
}
let m3 = new MethodFn()
console.log(m3)

11.5、方法属性修饰器

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值