Search code examples
typescriptoverloadingabstract-class

Why TypeScript excepts a correct return of a overriden method, even though it's not reachable?


I've implemented an abstract, generic RESTClient. Sometimes not all REST actions are implemented, so I want to throw an error in that case.

If I override the method TypeScript expects me to return the specified type, even though I throw the error. If I add return null it compiles, but the return is unreachable.

export class RESTClient<E extends { id: number }, D = Omit<E, 'id'>> extends Client {
  protected path: string;
  public constructor(path: string, token?: string) {
    super(token);
    this.path = path;
  }

  public update(entity: E) {
    return this.clientInstance.put<E>(`${this.path}/${entity.id}`, entity);
  }
}

export class ItemClient extends RESTClient<Item> {
  public constructor(token?: string) {
    super('items', token);
  }

  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  public delete(_entity: Item) {
    throw new Error('Not supported by API');
  }
}

demo

How can I correctly implement this in TypeScript (version 3.7.2)?


Solution

  • You can use never as the return type for the implementing method. It's assignable to every other type:

    interface Item { 
      id: number;
    }
    
    export class RESTClient<E extends { id: number }> {
      public update(entity: E) {
        return entity;
      }
    }
    
    export class ItemClient extends RESTClient<Item> {
      public update(entity: Item): never {
        throw new Error('Not supported by API');
      }
    }
    

    The suitable excerpt from the documentation:

    The never type is a subtype of, and assignable to, every type; however, no type is a subtype of, or assignable to, never (except never itself). Even any isn’t assignable to never.