Typescript

一、优点:

1、面向对象增强:TS是对面向对象思想进行了增强,使前端变成了强语言类型

(强语言类型:不会因赋值而改变数据类型,只能通过强制转换)

2、它有更多的规则和类型限制:代码具有更高的预测性、可控性,易于维护和调试;对模块、命名空间和面向对象 的支持,更容易组织代码开发大型复杂程序。

3、它是一个超集:它是以JavaScript为基础构建的语言,是一个编译到纯 JS 的有类型定义的 JS 超集,遵循当前以及未来的 ECMAScript规范。不仅能兼容现有的 JS 代码,它也拥有兼容未来版本的。

二、运行ts

1.新建ts 文件index.ts.

2.ts 语法在浏览器是无法运行得,所以需要编译成js 语法,使用如下命令 tsc index.ts (缺点:每次更新,都需要重新编译)

3.初始化文件夹和自动监测,执行如下命令:

 tsc --init

4.自动监测同步 JS 文件,执行如下命令:

 tsc -w

5.所有的 TS 文件必须通过下列方式编译成 JS 文件后,才能必须页面执行

 使用终端指令手动编译  tsc index.ts  使用终端指令自动编译 tsc --init  生成对应得 tsconfig.json文件  tsc -w  监测将ts文件编译成js文件。

三、ts的数据类型

语法:

let 变量:类型
let 变量:类型(number,boolean...)= 值(false/2/'sdf'...);
function fn(参数:类型,参数:类型):类型{
    。。。。。。
}

let u:undefined =undefined;
let n:null = null;
//多个类型
let a:number|string|undefined = 100
//表示c的对象中必须有name属性,其他为可选项
let c:{name:string,[propName:string]:any}

any和unknown类型的区别

any表示的是任意类型,一个变量设置类型为any后相当于对该变量关闭了ts的类型检测,不建议使用,声明变量时如果不指定类型,则ts解析器会自动判断变量的类型为any(隐式的any),他可以赋值给任何变量

unknown在赋值给任意确定类型的变量时会报错 ,unknown实际上就是一个安全类型的any

类型断言:(在将unknown类型赋值时,报错的解决办法)

有些情况下,变量的类型对于我们来说是很明确,但是TS编译器却并不清楚,此时,可以通过类型断言来告诉编译器变量的类型,断言有两种形式:

语法:变量 as 类型 / 变量

//第一种
let someValue: unknown = "this is a string";
let strLength: number = (someValue as string).length;
//第二种
let someValue: unknown = "this is a string";
let strLength: number = (<string>someValue).length;

枚举类型定义:

它是对 JavaScript 标准数据类型的补充,声明一组带名字的常量,当一个变量有多个取值的可能时,就可以定义为枚举型

 语法: enum xxx{     枚举名称  }

1、枚举类型

1.数字型枚举

当定义的枚举型成员是数字时,那么,该枚举就是数字型枚举,成员的数字既可以是指定的数字值,也可以是索引号,默认值从 0 开始,依次类推

 enum direction {
     up = 10,
     dowm = 88,
     left = 10,
     right = 99
 }

2.字符型枚举

在定义的枚举类型中,每个成员都是字符型字面量,它无法进行累加也不能初始化索引号,仅是给每个成员取了一个可读的名字, 反向映射。

 enum direction {
     up = 'up',
     dowm = 'down',
     left = 'left',
     right = 'right'
 }

3.异构型枚举

当一个定义好的枚举成员中,由数字和字符型联合构成,这种类型称之为异构型,即不同的类型构建在一起的枚举,(此类型很少使用)

  enum status1{
      success="ok",
      code=500
  }

4.常量型枚举

它是在普通枚举的基础上,使用 const 修饰符来定义,一旦定义成常量型的枚举,它的成员值只能使用常量,并删掉整个枚举定义内容

  let d = 199
  const enum direction{
      up=10,
      dowm,
      left=10,
      right = d   报错 
  }

2、反向映射

枚举类型中,通过成员名,可以很方便地访问到成员值,同时,通过成员值,也可以返回成员名称,这种方式称之为反向映射

 enum direction {
     up = 'up1',
     dowm = 'down1',
     left = 'left1',
     right = 'right1'
 }
 direction['dowm'] = 'down1'   反过来  direction['down1'] = 'down'

3、枚举合并

多个枚举类型可以分开定义,并不会冲突,分开后,在编译时会自动合并,不影响成员中值的访问,具体代码如下:

 enum direction {
     up = 10,
     dowm = 88,
     left = 10,
     right = 99
 }
 enum direction {
     forward = 1000,
     backward = 2000
 }
 console.log(direction)  合并到一块了

四、ts中的函数

可选参数和默认参数和剩余参数:可选参数? 可以不用传,注意:如果还有其他参数,可选参数不能作为第一个参数

可选参数在参数后+?
function add(x:number,y?:number):number{
     console.log(y)
     return y?x+y:x
 }

 默认参数就是给参数赋值默认值
function fn1(name:string,sex:string ='男',age?:number):string{
    return `${name}---${age}---${sex}`
 }

 剩余参数
 ...arr
function fn2(name:string="老杨",age?:number,...arr:any[]):string{
     console.log(name,age,arr)
      return ``
} 

fn2(undefined,32,'男','北京','已婚')    

五、接口

接口的语法:使用 interface 关键字,后面添加接口的名称,并使用大括号描述接口中各结构属性的类型,完成定义后,可以像普通的类型一样使用它

接口的作用类似于抽象类,不同点在于接口中的所有方法和属性都是没有实值的,换句话说接口中的所有方法都是抽象方法。接口主要负责定义一个类的结构,接口可以去限制一个对象的接口,对象只有包含接口中定义的所有属性和方法时才能匹配接口。同时,可以让一个类去实现接口,实现接口时类中要保护接口中的所有属性。

 interface Person{
      name:string, 
      age:number,
   }
      
 let p:Person = {
       name:"沈腾",
       age:40
   }

1、接口属性

接口属性有 普通属性, 可选属性(?),只读属性(readonly)

普通属性:就是正常的属性

可选属性: 在使用该接口时,可选属性可传可不传。

只读属性:只读属性使用后,不能再次修改。

 interface Person{
     name?:string, 
     readonly age:number,
  }
    
 let p:Person = {
      name:"沈腾",  可选属性 可传可不传
      age:40   只读属性不能修改
 }

2、接口定义函数

  fn 表示一种函数数据类型
 interface fn{
    (m:string):void
 }
 let f1:fn = function(m:string){
      console.log(m)
  }
 f1('xxxx')

接口中使用函数

如果在接口中有函数,可以在接口中直接定义

 interface Men{
      name?:string, 
      readonly age:number,
      say:(m:string,n:number)=>string  第一种写法
      say(m:string,n:number):string  第二种写法
  }

也可以使用接口定义,再引入到接口中,这两种方式都可以实现

  interface Say{
      (m:string,n:number):string
   }
   
  interface Men{
      name?:string, 
      readonly age:number,
      say:Say
   }
   let bichen:Men = {
       name:"xxx",
       age:30,
       say:function(m:string,n:number):string{
           return `${this.name}----${m}`
       }
   }

3、可索引接口

定义:主要是来用定义数组或对象数据类型的。

 1. 定义一个数组数据类型
 interface arr{
     [name:number]:any
 }
 let arr1:arr=['刘','关','张',100,{}];
 
 2. 定义一个对象数据类型
  interface obj{
      [name:string]:any
  }
  let obj1:obj={
      "sex":"男",
      age:20
  }

使用案例:

  interface child{
      name:string,
      age:number,
      say:()=>string,
      like:obj
  }
 ​
  let liuyan:child={
      name:"刘衍",
      age:20,
      say:():string=>{
        return ``
      },
      like:{
          "movie":"电影",
          "play":"lol"
      }
  }
  console.log(liuyan)

4、接口的继承

一个接口除被作为类型使用外,还可以被其他的接口继承,继承一个为单继承,二个以上为多接口继承,代码如下:

 

  定义 women接口
 interface women{
     name:string,
     age:number,
     cook:(m:string)=>string
 }
  定义 father接口
 interface father{
     work:()=>string
 }
 ​
  定义 son接口继承women,father接口
 interface son extends women,father{
     play:string,
     study:()=>string
 }
 ​
 let zhanhzhenda:son={
     name:"张郑达",
     age:20,
     cook:(m:string):string=>{
         return `我喜欢做${m}`
     },
     play:"lol",
     study:():string=>{
         return`我要毕业上班`
     },
     work:():string=>{
       return `我要敲代码`
     }
 }

六、类

在es5中使用函数创建类

  function Girl(name,age){
      this.name = name
      this.age = age
      this.say=function(){
 ​
      }
  }
 ​
  let fanbingbing = new Girl('范冰冰',40)
  let liuyifei = new Girl('刘亦菲',32)
  console.log(fanbingbing)
  console.log(liuyifei)

在es6中使用class 创建类

注意:类的构造函数:constructor(){} ,一般在实例化类的时候,传参需要用constructor 构造函数接收参数的情形。所以这种情况下,才需要在类里写构造函数。否则不写。

指在构造(实例化)一个类时,执行的函数,故称为构造函数,它也是一个普通的函数,也能定义形参,在构造时传递实参, 该构造函数在实例化类的时候执行。如下:即在 new C('张三')的执行。

  class Girl{
      name:string;
      age:number;
      say():string{
        return `大家好,我是${this.name}`
      }
      constructor(m:string,n:number){ 构造函数
          this.name = m
          this.age = n
      }
  }
 ​
  let guanzhilin = new Girl('关之琳',40)

1、类的继承

  • 在es6中,使用关键字 extends, super 实现类的继承。
  • 允许使用继承来扩展现有的类,可通过 extends 关键字来完成,派生类通常被称作子类,基类通常被称作超类
  • super() 表示调用父类的constructor(){} 方法
  • 如果父类和子类的有相同的方法名,调用子类的方法时,则会执行子类的方法。(也就是就近原则)
 // 定义 Girl类
 class Girl{
      name:string;
      age:number;
      say():string{
        return `大家好,我是${this.name}`
      }
      constructor(m:string,n:number){ 构造函数
          this.name = m
          this.age = n
      }
  }
 // 定义学生类 继承 Girl类
  class Student extends Girl{
      grade:string;
      study():string{
        return `我要学习web 前端`
      }
      say():string{
          return `子类中方法,我是${this.name}`
        }
      constructor(m:string,n:number,g:string){
          super(m,n)
          this.grade = g
      }
  }

2、类的修饰符

  • TS中属性具有三种修饰符:
    • public(默认值),可以在类、子类和对象中修改
    • protected ,可以在类、子类中修改
    • private ,可以在类中修改
  • 示例:
    • public
class Person{
    public name: string; // 写或什么都不写都是public
    public age: number;

    constructor(name: string, age: number){
        this.name = name; // 可以在类中修改
        this.age = age;
    }

    sayHello(){
        console.log(`大家好,我是${this.name}`);
    }
}

class Employee extends Person{
    constructor(name: string, age: number){
        super(name, age);
        this.name = name; //子类中可以修改
    }
}

const p = new Person('孙悟空', 18);
p.name = '猪八戒';// 可以通过对象修改
    • protected
class Person{
    protected name: string;
    protected age: number;

    constructor(name: string, age: number){
        this.name = name; // 可以修改
        this.age = age;
    }

    sayHello(){
        console.log(`大家好,我是${this.name}`);
    }
}

class Employee extends Person{

    constructor(name: string, age: number){
        super(name, age);
        this.name = name; //子类中可以修改
    }
}

const p = new Person('孙悟空', 18);
p.name = '猪八戒';// 不能修改
    • private
class Person{
    private name: string;
    private age: number;

    constructor(name: string, age: number){
        this.name = name; // 可以修改
        this.age = age;
    }

    sayHello(){
        console.log(`大家好,我是${this.name}`);
    }
}

class Employee extends Person{

    constructor(name: string, age: number){
        super(name, age);
        this.name = name; //子类中不能修改
    }
}

const p = new Person('孙悟空', 18);
p.name = '猪八戒';// 不能修改

属性存取器

    • 对于一些不希望被任意修改的属性,可以将其设置为private
    • 直接将其设置为private将导致无法再通过对象修改其中的属性
    • 我们可以在类中定义一组读取、设置属性的方法,这种对属性读取或设置的属性被称为属性的存取器
    • 读取属性的方法叫做setter方法,设置属性的方法叫做getter方法
    • 示例:
 class Person{
    private _name: string;

    constructor(name: string){
        this._name = name;
    }

    get name(){
        return this._name;
    }

    set name(name: string){
        this._name = name;
    }

}

const p1 = new Person('孙悟空');
console.log(p1.name); // 通过getter读取name属性
p1.name = '猪八戒'; // 通过setter修改name属性

3、静态属性

存在于类本身上面而不是类的实例上,即无须实例化就可以访问的属性,称之为静态属性,使用static开头

1、先看es5中类的静态属性表示如下:

2、es6中类的静态属性

 

 class Boy {
     static name1: string = '周杰伦';
     age: number;
     static say(): void {
         console.log(this.name1)
     }
     constructor(age: number) {
         this.age = age
     }
 }
 let jielun = new Boy(45)
 // jielun.say()
 console.log(Boy.say())

4、类类型接口

定义一个接口,声明一个类去实现(implements)接口,注意不是继承 如下:

 interface Person {
     name: string,
     age: number,
     say: (m: string) => void
 }
 // 使用类实现这个接口
 class Man implements Person {
     name: string;
     age: number;
     say(m: string): void {
         console.log(this.name)
     };
     constructor(name: string, age: number) {
         this.name = name
         this.age = age
     }
 }
 let wangyucao = new Man('小明', 10);

5、抽象类

抽象类做为其它派生类的基类使用。 它们一般不会直接被实例化。 不同于接口, 抽象类可以包含成员的实现细节。 abstract关键字是用于定义抽象类和在抽象类 内部定义抽象方法。

抽象类中的抽象方法不包含具体实现并且必须在派生类中实现。 抽象方法的语法与接口方法相似。 两者都是定义方法签名但不包含方法体。 然而,抽象方法必须包含 abstract关键字。

 // 1. 特点 抽象类不能实例化
 // 2. 抽象方法 不能写具体实现,必须在子类中写具体实现
 abstract class Animal {
     name: string;
     age: number;
     constructor(m: string, n: number) {
         this.name = m
         this.age = n
     }
     abstract run(): string
 }
 class Cat extends Animal {
     constructor(m: string, n: number) {
         super(m, n)
     }
     run(): string {
         return `${this.name}在跑步`
     }
 }
 let huahua = new Cat('花花', 5)
 console.log(huahua)

七、泛型

定义:先定义一个变量代表传入的类型,再使用该变量,因此,它是一种特殊的变量,只代表传入的数据类型,不是一个固定的值,而是传什么是什么,而这种类型变量称之为泛型

 // 普通函数1
 const fn = (x:number)=>{
     console.log(x)
 }
 // 普通函数2
 const fn2 = (x:string)=>{
     console.log(x)
 }
 // 普通函数调用
 fn(1)
 fn2('123')
 ​
 //使用泛型定义简化上述方式
 function fn<T>(x: T): T {
     return x
 }

1、泛型在接口中的使用

 interface fn1 <T>{
    (m: T): T
 }
 let f2: fn1 = function (m: any): any {
     return ``
 }

2、泛型在类中的使用

 class obj1<T>{
     arr: T[] = [];
     push(m: T) {
         this.arr.push(m)
     }
 }
 let obj = new obj1()
 obj.push('及时雨宋江')
 obj.push('黑旋风李逵')
 obj.push('智多星吴用')
 obj.push('豹子头林冲')
 obj.push(100)
 obj.push(true)

3、泛型约束

 type a = string | number | boolean  // 泛型加约束条件
 class obj1<T extends a>{
     arr: T[] = [];
     push(m: T) {
         this.arr.push(m)
     }
 }
 let obj = new obj1()
 obj.push('及时雨宋江')
 obj.push('黑旋风李逵')
 obj.push('智多星吴用')
 obj.push('豹子头林冲')
 obj.push(100)
 obj.push(true)

4、泛型数组2种方

 interface Array<T>{
     [name:number]:T
 }
 let arr3: Array<object> = [
     { name: "朱德", age: 60 },
     { name: "彭德怀", age: 60 },
     { name: "林彪", age: 66 }
 ]
 // 第二种方式
 interface newArr<T> {
     [name: number]: T
 }
 let arr4: newArr<object> = [
     { name: "刘伯承", age: 60 },
     { name: "叶剑英", age: 60 },
     { name: "徐向前", age: 66 }
 ]
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值