Search code examples
typescripttypeerror

TypeScript - type errors when using getters


I'm experimenting with Typescript, and attempting to implement a stack. The 'Stack' objects implements it's own interface, 'IStack' and extends an abstract 'Store' class.

interface IStack<T> {
  capacity: number;
  push(v: T): void;
  pop(): T | undefined;
  peek(): T | undefined;
  size(): number;
}

abstract class Store<T> {
  protected storage: T[] = [];

  get size(): number {
    return this.storage.length;
  }

  abstract isFull(): boolean;
}

class Stack<T> extends Store<T> implements IStack<T> {
  constructor(public capacity: number = Infinity) {
    super();
  }

  push(v: T): void {
    if (this.isFull()) {
      throw new Error("Maximum capacity of stack reached.");
    }
    this.storage.push(v);
  }

  pop(): T | undefined {
    return this.storage.pop();
  }

  peek(): T | undefined {
    return this.storage[this.size - 1];
  }

  isFull(): boolean {
    return this.capacity === this.size;
  }
}

let stack = new Stack<number>(4);
stack.push(1);
stack.push(2);
stack.push(3);
stack.push(4);
console.log(stack);

This code generates the following error:

Class 'Stack<T>' incorrectly implements interface 'IStack<T>'.
  Types of property 'size' are incompatible.
    Type 'number' is not assignable to type '() => number'.ts(2420)

As far as I can tell, there is no assignment to the size property. So I don't really understand what the error is telling me.


Solution

  • The easiest solution is to change the definition of the size in the interface to be getter:

    interface IStack<T> {
      capacity: number;
      push(v: T): void;
      pop(): T | undefined;
      peek(): T | undefined;
      get size(): number;
    }
    

    Alternatively, you could use size as a method, not a property:

    abstract class Store<T> {
      protected storage: T[] = [];
    
      size(): number {
        return this.storage.length;
      }
    
      abstract isFull(): boolean;
    }
    

    Stack:

    class Stack<T> extends Store<T> implements IStack<T> {
      constructor(public capacity: number = Infinity) {
        super();
      }
    
      push(v: T): void {
        if (this.isFull()) {
          throw new Error('Maximum capacity of stack reached.');
        }
        this.storage.push(v);
      }
    
      pop(): T | undefined {
        return this.storage.pop();
      }
    
      peek(): T | undefined {
        return this.storage[this.size() - 1];
      }
    
      isFull(): boolean {
        return this.capacity === this.size();
      }
    }