TS定义类,定义接口,枚举

484 阅读2分钟

定义类

在 TypeScript 中,我们也是通过 Class 关键字来定义一个类, 使用 constructor 定义构造函数。

class Animal {
    public name: string;
    constructor(name: string) {
        this.name = name;
    }
    sayHi(): string {
        return `我的名字 ${this.name}`;
    }
}

继承

TS中的继承ES6中的类的继承极其相似,子类可以通过extends关键字继承一个类 例如 在构造器里访问 this 的属性之前,一定要调用 super()  ,这个是 TypeScript 强制执行的一条重要规则。

 class Person {
        constructor (name) {
          // 等价于我们的构造函数体
          this.name = name
        }

        // 原型上的方法
        sayHi () {
          console.log('hello world')
        }
      }

      // 2. 准备一个子类
      //    一个继承自 Person 的 Student 子类
      class Student extends Person {
        constructor (age, name) {
          // super(name) // 就相当于我们 es5 的借用构造函数继承
          // 只不过不需要我们写 call 去改变 this 指向了
          // 直接帮我们改变好 this 指向了, 我们只需要传递参数就可以了

          super(name)
          this.age = age
        }

        son () {
          console.log('我是 子类的方法')
        }

      }

      var s1 = new Student(18, 'Jack')
      console.log(s1)

ES6一样,子类构造函数必须加上super()执行父类的构造constructor函数

所以,大家常常说,一个子类实例,同时也是父类的实例

类的修饰符

TypeScript 中有三类访问修饰符,分别是: publicprivateprotected不写默认为 public

  • public :自己、自己的子类 和其他类都可以访问 (默认值)
  • protected :受保护的 自己和自己的子类能访问, 其他类不能访问
  • private :私有的 只能自己访问,自己的子类不能访问,其他类更不能访问
// 定义一个类
class Person {
    // name:string
    // private name:string
    protected name:string

    constructor(name:string){
        this.name = name
    }
    public eat(){
        console.log(`${this.name},好吃`)   
    }

}

// 定义一个子类
class Student extends Person {
    constructor(name:string){
        super(name)
    }
    play(){
        // 当name为protected时,子类中也可访问;
        // 但如果其为private,子类中则无法访问
        console.log('like play',this.name)  
    }
}

const p1 = new Person('张三')
// console.log(per.name)   // name 为私有,外部无法访问
per.eat()

定义接口

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

// 定义接口
class Person {
    name: string;
    age: number;
  }
  interface Man extends Person {
    money: string;
  }
  let me: Man = {
    name: 'funlee',
    age: 18,
    money: '100W'
  }

枚举

使用枚举我们可以定义一些带名字的常量。 使用枚举可以清晰地表达意图或创建一组有区别的用例。 TypeScript支持数字Number的和基于字符串String的枚举。

数字枚举

  enum Direction {
      Up = 1,
      Down,
      Left,
      Right
  }

如上,我们定义了一个数字枚举, Up使用初始化为 1。 其余的成员会从 1开始自动增长。 换句话说, Direction.Up的值为 1, Down为 2, Left为 3, Right为 4

我们还可以完全不使用初始化器:

enum Direction {
    Up,
    Down,
    Left,
    Right,
}

现在, Up的值为 0, Down的值为 1等等。 当我们不在乎成员的值的时候,这种自增长的行为是很有用处的,但是要注意每个枚举成员的值都是不同的。

字符串枚举

字符串枚举的概念很简单,但是有细微的 运行时的差别。 在一个字符串枚举里,每个成员都必须用字符串字面量,或另外一个字符串枚举成员进行初始化。


enum Direction {
    Up = "UP",
    Down = "DOWN",
    Left = "LEFT",
    Right = "RIGHT",
}

由于字符串枚举没有自增长的行为,字符串枚举可以很好的序列化。 换句话说,如果你正在调试并且必须要读一个数字枚举的运行时的值,这个值通常是很难读的 - 它并不能表达有用的信息(尽管 反向映射会有所帮助),字符串枚举允许你提供一个运行时有意义的并且可读的值,独立于枚举成员的名字。

参考文献

TypeScript中文网 · TypeScript——JavaScript的超集 (tslang.cn)