TS 基础学习(三)

class
  TypeScript全面支持ES2015中引入的class关键字,并为其添加了类型注解和其他语法(比如,可见修饰符等)
  class Person {
    name: string = 'a'
  }
  const p = new Person()
  console.log(p); // Person { name: 'a' }
  1、根据TS中的类型推论,可以知道Person类的实例对象p的类型是Person。
  2、TS中的class,不仅仅提供了class的语法功能,也作为一种类型存在
实例属性初始化
  class Person {
     name = 'a'
     age: number
  }
  1、声明成员age,类型为number(没有初始值)
  2、声明成员name,并设值初始值,此时,可省略类型注解(TS会自动推论为string类型)
class类中的构造函数
  class Person1 {
     age: number
     gender: string
     constructor(age: number, gender: string) {
        this.age = age
        this.gender = gender
      }
   }
   1、成员初始化(比如age:number)后,才可以通过this.age来访问实例成员
   2、需要为构造函数指定类型注解,否则会被隐式推断为any;构造函数不需要返回值类型
class中的实例方法
   class Point {
       x = 10
       y = 10
       scale(n: number): void {
           this.x *= n
           this.y *= n
       }
     }
    1、方法的类型注解(参数和返回值)与函数用法相同
class 类的继承
  类继承的两种方式: 1.extends(继承父类); 2 implements(实现接口)
  // 定义一个接口
  interface Singable {
     sing(): void
   }
   class Person implements Singable {
       sing(): void {
           console.log('实现接口的方法');
       }
    }
   const p = new Person()
    p.sing()
    1、通过implements关键字让class实现接口
    2、Person类实现接口Singable意味着,Person类中必须提供Singable接口中指定的所有方法和属性
class 类成员可见性修饰符
    类成员可见性: 可以使用TS来控制class的方法或属性对于class外的代码是否可见
    可见性修饰符包括:public(公有的)、protected(受保护的)、private(私有的)
    public: 表示公有的、公开的,公有成员可以被任何地方访问,默认public
    class Animal {
        public move() {}
     }
    1、在类属性或方法前面添加public关键字,来修饰该属性或方法是公有的。
    2、因为public是默认可见性,所以,可以直接省略。
    protected:表示受保护的,仅对其声明所在类和子类中(非实例对象)可见
    class Animal1 {
        protected move() {}
     }

      class Dog extends Animal1 {
          bark() {
              console.log('1111');
              this.move()
      }
     1、在类属性或方法前面添加protected关键字,来修饰该属性或方法是受保护的
     2、在子类的方法内部可以通过this来访问父类中受保护的成员,但是,对实例不可见
     private: 表示私有的,只在当前类中可见,对实例对象以及子类也是不可见的。
     class Animal2 {
          private move() {}
          walk() {
          this.move()
         }
     }
    1、在类属性或方法前面添加private关键字,来修饰该属性或方法是私有的。
    2、私有的属性或方法只在当前类中可见,对子类和实例对象也都是不可见的
readonly 只读修饰符
    readonly:表示只读,用来防止在构造函数之外对属性进行赋值。
    class Person1 {
         // 只要是readonly修饰的属性,必须手动提供明确的类型
        readonly age: number = 18
        constructor(age: number) {
        this.age = age
     }
    }
   1、使用readonly关键字修饰该属性是只读的,注意只能修饰属性不能修饰方法。
   2、注意: 属性age后面的类型注解(比如,此处的number)如果不加,则age的类型为18(字面量类型)
   3、接口或则{} 表示的对象类型,也可以使用readonly。
类型兼容性
  TS采用的是结构化类型系统, 也叫做duck typing(鸭子类型), 类型检查关注的是值所具有的形状, 也就是说,在结构 类型系统重, 如果两个对象具有相同的形状,则认为他们属于同一类型。
   class Point { x: number; y: number }
   class Point2D { x: number; y:number }
   const p: Point = new Point2D()
Point和Point2D是两个名称不同的类
   1、变量p的类型显示标注为Point类型,但是,它的值确实Point2D的实例, 并且没有类型错误
   2、因为TS是结构化类型系统,只检查Point和Point2D的结构是否相同(想通,都具有x和y两个属性,属性类型也想通)
   3、但是,如果在Nominal Type System中(比如,C#、Java等),他们是不同的类,类型无法兼容。
   注意: 在结构化类型系统重,如果两个对象都具有相同的形状,则认为他们属于同一类型,这种说法并不准确
   更准确的说法:对于对象类型来说, y的成员至少与x相同, 则x兼容y(成员多的可以赋值给少的)
   class Point { x: number; y: number }
   class Point3D { x: number; y:number; z: number }
   const p: Point = new Point3D()
   1、Point3D的成员至少与Point相同, 则Point兼容Point3D
   2、所以,成员多的Point3D可以赋值给成员少的Point
接口(interface)兼容性
   除了class 之外,TS中的其他类型也存在相互兼容的情况,包括:接口兼容性、 函数兼容性等
   接口之间的兼容性,类似于class。并且class和interface 之间也可以兼容
   interface Point { x: number; y: number }
   interface Point2D { x: number; y: number }
   interface Point3D { x: number; y: number; z: number }

   let p1: Point = { x: 10, y: 20}
   let p2: Point2D = p1

    let p3: Point3D = { x: 10, y: 20, z: 30}
    p2 = p3

    // 定义一个类Point4D 和 Point3D的结构完全一致
   class Point4D {
       x: number; y: number; z: number
   }
   // 声明的类型是接口, 但是可以把类的实力对象复制给p4
   let p4: Point2D = new Point4D()
   console.log(p4);// Point4D { x: 10, y: 20, z: 30 }
函数兼容性
   函数之间兼容性比较复杂需要考虑:1.参数个数、2.参数类型、3.返回值类型
  参数个数,参数多的兼容参数少的(或则说,参数少的可以赋值给参数多的)
  1、参数少的可以赋值给参数多的,所以f1可以赋值给f2
  2、数组forEach方法第一个参数是回调函数, 该示例中类型为:(value: string, index: number, array:string[]) => void
  3、在JS中省略用不到的函数参数实际上是很常见的,这样的使用方式,促使了TS中函数类型之间的兼容性
  4、并且因为回调函数是有类型的,所以,TS会自动推倒出参数item、index、array的类型
  参数类型,想同位置的参数类型要相同(原始类型)或兼容(对象类型)
  type F1 = (a: number) => void
  type F2 = (b: number) => void

  let f1: F1 = (a) => { }
  let f2: F2 = f1
  函数类型F2兼容函数类型F1,因为F1和F2的第一个参数类型相同
  注意: 此处与前面讲的接口兼容性冲突
  技巧:将对象拆开,把每个属性看做一个个参数,则,参数少的(f3)可以赋值给参数多的(f4)
  返回值类型,只关注返回值类型本身即可
  1、如果返回值类型是原始类型,此时两个类型要相同,比如f5和f6
  2、如果返回值类型是对象类型, 此时成员多的可以赋值给成员少的,比如f7和f8

posted @ 2024-06-27 14:03  等风来灬  阅读(17)  评论(0编辑  收藏  举报