typeScript 接口和类

工具: PlayGround


接口

接口用来定义对象的结构和类型,描述对象应该具有哪些属性和方法。

它仅用于声明,而不是实现; 这对于编写可重用的代码非常有用。它可用于:

关键字是interface, 注意:它只是作为TypeScript的一部分,并不会转换为JavaScript

  • 数组定义
interface data {
    [index:number]: number,
}

// 类型一致,没有问题
let numList_1: data = [1, 2, 3];
// Type 'string' is not assignable to type 'number'
let numList_2: data = [1, "", 3];
  • 对象的定义
// 方式1
interface Data_1 {
    name: string,
    age: number,
}
let data_1: Data_1 = {
    name: "hello",
    age: 20,
}
console.log(data_1);

// 方式2
interface Data_2 {
    name: string;
    age: number;
    // 可选属性, 表示可以选择不赋值
    sex?: number;
    // 只读属性,表示一旦赋值后不可修改                       
    readonly id:number | string;   
}
let data_2: Data_2 = {
    name: "hello",
    age: 20,
    id : "0001",
}
data_2.age = 10;
// Error: Cannot assign to 'id' because it is a read-only property
data_2.id = 10;

  • 作为类实现
interface Person {
  name: string;
  age: number;
  greet: () => void;
}

// 通过implements实现接口
class Student implements Person {
  name: string;
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  greet() {
    console.log(`Hello, my name is ${this.name}`);
  }
}

let student = new Student("ok", 20);
student.greet();        // "Hello, my name is ok" 

typeScript中类的使用,主要通过class来创建类对象,通过new来实例化类对象, 支持特性:

  • instanceof检测对象类型

  • 访问权限publicprotectedprivate

  • 函数重载

  • 继承或重写

  • 静态成员和方法

基本的使用:

class Demo {
    private _name: string = "";
    private _age: number = 0;

    // 构造函数
    constructor(name:string) {
        this._name = name;
    } 

    public log() {
        console.log(`Demo 的名字为${this._name}`);
    }
}
let demo = new Demo("demo");
console.log(typeof(demo));              // "object" 
console.log(demo instanceof Demo);      // true    

函数重载

类的函数重载的编写方式,不要直接实现:

class Demo {
  private _name: string = "";
  private _age: number = 0;

  // 构造函数
  constructor(name:string) {
    //
  } 

  // Error: Multiple constructor implementations are not allowed
  // 原因在于如果实现,编译器创建对象不知道调用哪个构造函数
  constructor(name: string, age:number) {
    //
  }
}

可以通过采用声明和可选参数的方式来实现:

// 实例1
class Demo {
  private _name: string = "";
  private _age: number = 0;

  // 构造函数
  constructor(name:string);
  constructor(name: string, age:number);
  constructor(name: string, age?:number) {
    this._name = name;
    if (age) {
      this._age = age;
    }
  }
}

// 实例2:
class Calculator {
  add(a: number, b: number): number;
  add(a: string, b: string): string;
  add(a: any, b: any): any {
    if (typeof a === 'number' && typeof b === 'number') {
      return a + b;
    } else if (typeof a === 'string' && typeof b === 'string') {
      return a.concat(b);
    } else {
      throw new Error('Invalid arguments');
    }
  }
}

const calculator = new Calculator();

console.log(calculator.add(1, 2));      // 3
console.log(calculator.add('Hello', ' World')); // Hello World

继承和重写

继承的话,使用extends, 如果对基类中的方法重新编写,就是重写

// 定义接口,简单的实例可以忽略;增加的话,有助于理解代码和重写代码相关
interface Animal {
    sound(): void;
}

// 实现接口
class Cat implements Animal {
    private _breed: string;
    private _name: string = "Cat";

    constructor(breed: string) {
        this._breed = breed;
    }

    // 通过get和set的方式设置对象变量属性
    get Name():string {
        return this._name;
    }
    set Name(name: string) {
        this._name = name;
    }

    sound(): void {
        console.log("猫");
    }
}

// 继承
class DomesticCat extends Cat {
    public log() {
        console.log("this is DomesticCat");
    }
}

// 重写
class WildCat extends DomesticCat {
    sound(): void {
        console.log("野猫叫声");
    }
}

const domesticCat = new DomesticCat("domesticCat");
domesticCat.Name = "短毛猫"
console.log(`cat Name: ${domesticCat.Name}`);   //"cat Name: 短毛猫" 
domesticCat.sound(); // 猫

// 
const wildCat = new WildCat("豹猫");
wildCat.sound();    // 野猫叫声

注意:

  • 如果未声明访问权限publicprotectedprivate,则默认为public
  • 对于变量,建议开头增加下划线_ 表示私有
  • 可以多继承,只需要在extends后面添加类接口即可
  • 注意区分implementsextends,前者主要用于对interface声明的方法等进行实现, 而后者主要应用于已经实现后的方法进行继承或重写。

Static

静态变量或方法在类中声明后,可以不通过new对象直接赋值或使用,但赋值后不可在改变。

class Demo {
    static value: number;
    static getValue() {
        console.log(`static value: ${Demo.value}`);
    }
}
Demo.value = 10;
Demo.getValue();        //"static value: 10" 

它常用于编写单例模式,注意: 构造函数设置为私有,以保证对象的唯一性

class Singleton {
  private static instance: Singleton;

  private constructor() {
    // 私有化构造函数,防止外部实例化
  }

  public static getInstance(): Singleton {
    if (!Singleton.instance) {
      Singleton.instance = new Singleton();
    }
    return Singleton.instance;
  }

  public greet(): void {
    console.log("Hello");
  }
}

// 创建单例实例
const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();

console.log(instance1 === instance2); // true

instance1.greet(); // "Hello" 
instance2.greet(); // "Hello" 

const

作为常量使用,在类中使用注意:

  • 只能用于修改基本数据类型和对象属性字面量,不可用于修饰引用类型
  • 如果声明const 一定要记得初始化,不能在构造函数或其他函数进行初始化
  • 声明以后,其本质就是readonly 只读属性
class MyClass {
  readonly PI: number = 3.14;
  readonly config: { name: string, age: number } = { name: "John", age: 25 };

  constructor() {
    // this.PI = 3.14159;  // 错误,无法对只读属性进行重新赋值
    // this.config = { name: "Alice", age: 30 }; // 错误,无法对只读属性进行重新赋值

    this.config.name = "Alice"; // 正确,可以修改对象字面量属性的值
    this.config.age = 30; // 正确,可以修改对象字面量属性的值
  }

  printInfo(): void {
    console.log(`PI: ${this.PI}`);
    console.log(`Name: ${this.config.name}, Age: ${this.config.age}`);
  }
}

const myObj = new MyClass();
myObj.printInfo();

// "PI: 3.14" 
// "Name: Alice, Age: 30" 

你可能感兴趣的:(typeScript,typescript)