2-1-12 TS Class

Posted 沿着路走到底

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2-1-12 TS Class相关的知识,希望对你有一定的参考价值。

定义类和成员

class Point 
    x: number
    y: number
      
    constructor(x : number, y : number)
        this.x = x
        this.y = y
    
    
    public add(p : Point) : Point 
      return new Point(p.x + this.x, p.y + this.y)
    
  

  const p = new Point(0, 0)
  const newP = p.add(new Point(1, 1))
  console.log(newP)

成员函数的重载

class Point 
		// ...
    
    public add(x : number, y : number) : Point;
    public add(p : Point) : Point;
    public add(x : number | Point, y? : number) 
      if(typeof x === 'number') 
          return new Point(this.x + x ,  this.y + y!)
      
      const p = x
      return new Point(this.x + p.x, this.y + p.y)
    
  

  const p = new Point(0, 0)
  const newP = p.add(new Point(1, 1))
  console.log(newP)

重载可以获得更好的书写提示体验。

Getter / Setter

获取和设置变成两个方法,隐藏了内部具体的实现。

class C 
  _length = 0;
  get length() 
    return this._length;
  
  set length(value) 
    this._length = value;
  

不推荐这样的实现,推荐:

可读性,语义更强

class C 
  _length = 0;
  getLength() 
    return this._length;
  
  setLength(value) 
    this._length = value;
  

索引器

class Arr<T> 
    [i : number] : T
  

  const a = new Arr<number>()
  a[10] = 100
  console.log(a[10]) // 100

类型继承

interface BasicAddress 
  name?: string;
  street: string;
  city: string;
  country: string;
  postalCode: string;

 
interface AddressWithUnit extends BasicAddress 
  unit: string;

类的继承

class Animal 
  move() 
    console.log("Moving along!");
  

 
class Dog extends Animal 
  woof(times: number) 
    for (let i = 0; i < times; i++) 
      console.log("woof!");
    
  

实战中尽量使用组合:

interface Movable 
    move() : void;


class Dog implements Movable 
    move () 
        console.log('move dog')
    

或者泛型:

class Movable<T extends Animal> 
    animal : T
    
    move()
        console.log(`$animal.getName() is moving`)
    

划重点:继承会加重耦合,组合和泛型不会。

成员可见域

- public

- protected

- private

`public` `private` `protected` 这3个和其他语言一样,具体的:

`public` 成员允许所有程序访问,如果不标识任何约束,那么默认就是`public`

class Point 
    x : number

// x可以被任意程序访问

`private` 成员只允许在当前类中访问。

class Point 
    private x : number
    constructor()
        this.x = x // 成立
    
    
    getX()
        return this.x
    


const p = new Point()
console.log(p.x)
// Error : Property 'x' is private and only accessible within class 'Point'.ts(2341)

`protected` 允许在当前类和它的继承类中访问成员。

class Animal 
    private _name1;
    protected _name2;


class Dog extends Animal
    getName1()
        return this._name1 // Error
    
    
    getName2()
        return this._name2 // pass
    

静态成员

class MyClass 
  static x = 0;
  static printX() 
    console.log(MyClass.x);
  

console.log(MyClass.x);
MyClass.printX();

静态成员和类的实例没有关系,静态成员、静态方法都绑定在类型本身上。

静态成员也会继承:

class Base 
  static getGreeting() 
    return "Hello world";
  

class Derived extends Base 
  myGreeting = Derived.getGreeting();

保留的特殊静态成员名称:

class S 
  static name = "S!";
// Error : Static property 'name' conflicts with built-in property 'Function.name' of constructor function 'S'.

为什么没有静态类?

在 Java中有静态类, 静态类是相对类的嵌套的概念,在JS虽然也存在类的嵌套,但是遵循闭包的逻辑,比如:

class A 
    x : number
    foo()      
      const y = 0
      class B
        bar()
          this.x // Property 'x' does not exist on type 'B'
          console.log(y)
        
      
      return B
    
  

因为有B包的逻辑,就不太适合再增加,让嵌套类可以访问外部类成员的逻辑了。 逻辑太复杂,不利于程序员写程序。

类型守卫

class FileSystemObject 
  isFile(): this is FileRep 
    return this instanceof FileRep;
  
  isDirectory(): this is Directory 
    return this instanceof Directory;
  
  isNetworked(): this is Networked & this 
    return this.networked;
  
  constructor(public path: string, private networked: boolean) 

 
class FileRep extends FileSystemObject 
  constructor(path: string, public content: string) 
    super(path, false);
  

 
class Directory extends FileSystemObject 
  children: FileSystemObject[];

 
interface Networked 
  host: string;

 
const fso: FileSystemObject = new FileRep("foo/bar.txt", "foo");
 
if (fso.isFile()) 
  fso.content;  
  //const fso: FileRep
 else if (fso.isDirectory()) 
  fso.children;
  //const fso: Directory
 else if (fso.isNetworked()) 
  fso.host;
  
  //const fso: Networked & FileSystemObject

抽象类

抽象类不可以实例化

abstract class Base 
  abstract getName(): string;
 
  printName() 
    console.log("Hello, " + this.getName());
  

 
const b = new Base();
// Cannot create an instance of an abstract class.

必须继承:

class Derived extends Base 
  getName() 
    return "world";
  

 
const d = new Derived();
d.printName();

类型的关系

TS会通过成员去思考类型是否一致:

class Point1 
  x = 0;
  y = 0;

 
class Point2 
  x = 0;
  y = 0;

 
// OK
const p: Point1 = new Point2();

另一个例子:

class Person 
  name: string;
  age: number;

 
class Employee 
  name: string;
  age: number;
  salary: number;

 
// OK
const p: Person = new Employee();

最后一个例子:

class Empty 
 
function fn(x: Empty) 
  // can't do anything with 'x', so I won't

 
// All OK!
fn(window);
fn();
fn(fn);

1

以上是关于2-1-12 TS Class的主要内容,如果未能解决你的问题,请参考以下文章

TypeScript 专题之 Ts 中的类(class)

TypeScript 专题之 Ts 中的类(class)

使用 TS 和 class 实现一个简易 Promise

vue-cli3 + ts + vuex

[TS] Class Properties Public, Private and Read Only Modifiers

如何省略错误:[ts] <class function name> 的推断类型引用了无法访问的“this”类型。需要类型注释