好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

TypeScript 之 Class

class

private 和 # 的区别

前缀 private 只是TS语法,在运行时不起作用,外部能够访问,但是类型检查器会报错

class Bag { private item: any }

修饰符 # 是JS语法,是运行时私有的,并且在JavaScript引擎内部强制执行,它只能在类内部访问

class Bag { #item: any }

修饰符 #,MDN 参考链接: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes/Private_class_fields#%E8%AF%AD%E6%B3%95

类型和值(Type and Value)

class 能够作为一个类型和一个值,但是最好 不要这么做

 class Bag { }
const a: Bag  =  new   Bag()
class C implements Bag { } 

常用语法(common Syntax)

 class User {
  name: string   //   必须声明才能在 constructor 赋值 
   constructor(name: string) {
      this .name =  name
  }
} 

以下是上面简写,public 可换成 private ,public readonly,protected, 等等......,但不能是 js 语法 static 和 # 修饰符

 class User {
  constructor(public name:string){}
} 

 其它常用语法

 interface Updatable { }
type Serializzable  =  {}
class Account { }
  //   继承 Account 类,实现 Updatable 接口 和 Serializzable 类型 
 class User extends Account implements Updatable, Serializzable {
  id: string;
  displayName ?:  boolean ;  //    可选 
  name!: string;  //   告诉类型检查器 name 有值 
  #attributes: Map<any, any>;  //   私有属性,js语法 
  roles = ["user"];  //   默认值 
  readonly createdAt =  new  Date();  //  只读属性 
   constructor(id: string) {
    super()
      this .id =  id
      this .#attributes =  new   Map()
  }

  setName(name: string) {   this .name = name }  //   原型方法 
  verifyName = (name: string) => {  this .name = name }  //   实例方法 

   //   函数重载 
  sync(): Promise<{}> 
  sync(cb: (result: string) => void ):  void 
   //   方法类型声明完成,后要接着方法实现 
  sync(cb?: (result: string)=> void ):  void  | Promise<{}> {}
    //   Getters and Setters 
  get accountID(){ return  123 }
  set accountID(value: number){   /*  * ...   */   }
    //   protected 只能在类和继承类的后代类中使用,不可以在实例中使用 
   protected handleReques(){}
    //   静态类型,js语法 
  static #userCount = 0  //   只能在静态方法里使用 
  static registerUser(user: number){ this .#userCount =  user}
} 

泛型(Generics)

class Box<Type> {
  constructor(public content:Type){}
}
const stringBox  =  new  Box("a package" )
  //   stringBox: Box<string> 

 

抽象类(Abstract Classes)

在 TypeScript 中,类,方法和字段都可以是抽象的。抽象方法和字段都只能出现在抽象类中。

抽象类自身不能实例化,只能作为派生类的基类,派生类必须实现抽象类的所有抽象方法和字段。

 abstract class Base {
  abstract getName(): string;

  printName() {
    console.log( "Hello, " +  this  .getName());
  }
}
const b  =  new  Base();  //   错误,无法创建抽象类的实例。 
 
class Derived extends Base {
    //   必须实现该抽象函数 
   getName() {
      return  "world" ;
  }
}
const d  =  new   Derived();
d.printName(); 

抽象构造签名(Abstract Construct Signatures)

有时你想接受一个构造函数,产生一个实例,这个构造函数是某个 抽象类派生的类 。

Bad!这种写法,在传递抽象类的时候 TypeScript 没有报错,只有new 实例化才报错

 function  greet(ctor:  typeof   Base) {
  const instance  =  new  ctor();  //   无法创建抽象类的实例。 
   instance.printName();
}
greet(Base); 

Great!接受一个带有构造签名的参数,这种写法,在传递抽象类的时候 TypeScript 就报错了

 function  greet2(ctor:  new  () =>  Base) {
  const instance  =  new   ctor();
  instance.printName();
}
greet2(Derived);
greet2(Base); 

抽象类继承抽象类

抽象类继承抽象类,两抽象类会进行合并,出现相同名称的抽象方法和字段,如果不同类型会报错,但是相同类型,子类型,any,这些都不会报错。

 abstract class Base {
  abstract getName(): string;
  abstract asd: string
  printName() {
    console.log( "Hello, " +  this  .getName());
  }
}
abstract class Bag extends Base {
  abstract getName(): any;    //   相同抽象方法,返回值改为any,不报错 
  abstract asd: '456'  //   相同抽象字段,返回值改为 string 子类型,不报错 
 }
class Derived extends Bag {
  constructor(public asd:  '456' ) {
    super()
  }
  getName() {
      return  123 ;
  }
}
const d  =  new  Derived('456' );
d.printName(); 

这里的 extends 是js 语法,类只能继承一个。并不是 ts 的 extends, 用于 Interface  扩展,和类型缩窄

class Derived extends Bag, Base {} // 错误

修饰器和属性(Decorators and Attributes)

在 "tsconfig" 中打开 "experimentalDecorators"

可以在类,方法,方法参数,属性和访问器上用修饰器

import { Syncable, triggerSync, preferCache, required } from "mylib" 
@Syncable
class User {
  @triggerSync()   //   方法 
   save() { }
  @preferCache(  false )  //   访问器 
   get displayName() { }
  update(@required info: Partial <User>) { }  //   方法参数 
}

一个声明应用多个装饰器,会 从 下到上调用

 function   first(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  console.log( "first(): called" );
};
  function   second(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  console.log( "second(): called" );
};

class ExampleClass {
    //   单行,多行,两种写法 
   @first @second method() { }
    //   @first 
   //   @second 
   //   method() { } 
 }
const exampleClass  =  new   ExampleClass();
exampleClass.method()
  //   second(): called  
//   first(): called 

一个声明应用多个装饰器工厂(decorator factories),会 从上到下调用 后, 再 从下到上 调用 返回的函数

 function   first() {
  console.log( "first(): factory evaluated" );
    return   function   (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log( "first(): called" );
  };
}

  function   second() {
  console.log( "second(): factory evaluated" );
    return   function   (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log( "second(): called" );
  };
}

class ExampleClass {
  @first()
  @second()
  method() { }
}
const exampleClass  =  new   ExampleClass();
exampleClass.method()

  //   first(): factory evaluated  
//   second(): factory evaluated  
//   second(): called  
//   first(): called 

Decorator Evaluation

应用于类内部各种声明的装饰器,有一个明确定义的顺序:

实例成员,(参数装饰器,其次是方法),(访问器),(属性装饰器), 这三者按照声明顺序调用 静态成员,(参数装饰器,其次是方法),(访问器),(属性装饰器), 这三者按照声明顺序调用 构造函数参数修饰器 类修饰器

 还有一个注意点,参数修饰器中,越往后的参数修饰器,越早调用

 function   classDecorator(constructor: Function) {
  console.log( "classDecorator" );
};
  function   propertyDecorator(name: string) {
    return   function   (target: any, propertyKey: string) {
    console.log(name);
  }
}
  function   parameterDecorator(name: string) {
    return   function   (target: any, functionName: string, index: number) {
    console.log(name);
  }
}
  function   methodDecorator(name: string) {
    return   function   (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log(name);
  };
}
  function   accessorDecorator(name: string) {
    return   function   (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log(name);
  }
}


@classDecorator
class ExampleClass {

  constructor(@parameterDecorator( "constructorParameter") greeting: string, @parameterDecorator("constructorParameter2" ) public appService: string) {
      this .greeting =  greeting
  }

  @accessorDecorator( "staticAccessor") static get x() { return  123 }
  @propertyDecorator( "staticProperty" ) static id: number
  @methodDecorator( "staticMethod" ) 
  static smethod(@parameterDecorator( 'staticParmeter' ) value: string) { }

  @propertyDecorator( "instanceProperty" ) greeting: string
  @methodDecorator( "instanceMethod" )
  method(value: string, @parameterDecorator( 'instanceParmeter' ) value2: string) { }
  @accessorDecorator( "instanceAccessor") get x() { return  123 }

}
const exampleClass  =  new  ExampleClass('asd', 'wew' );
exampleClass.method( 'a', 'b' )

  //   [LOG]: "instanceProperty"   
//   [LOG]: "instanceParmeter"   
//   [LOG]: "instanceMethod"   
//   [LOG]: "instanceAccessor"   
//   [LOG]: "staticAccessor"   
//   [LOG]: "staticProperty"   
//   [LOG]: "staticParmeter"   
//   [LOG]: "staticMethod"   
//   [LOG]: "constructorParameter2"   
//   [LOG]: "constructorParameter"   
//   [LOG]: "classDecorator"  

 

感谢观看,欢迎互相讨论与指导,以下是参考资料链接?

https://www.typescriptlang.org/static/TypeScript%20Classes-83cc6f8e42ba2002d5e2c04221fa78f9.png

 

查看更多关于TypeScript 之 Class的详细内容...

  阅读:47次