6

Simple and common Angular2+ data service that handles errors and uses Promises:

// imports skipped

class DataType {}

class Error {
  constructor(error: HttpResponse) {
    this.error = error.json()
  }
}


@Injectable()
export class MyService<DataType> {
  apiUrl = 'my/url';
  constructor(protected http) {}

  get(): Promise<DataType[] | Error> {
    return this.http
    .get(this.apiUrl)
    .toPromise()
    .then(response => response.json())
    .catch(this.handleError);
  }

  protected handleError(error: HttpResponse): Promise<Error> {
    console.error('An error occurred', error);
    return Promise.reject(new Error(error));  
  }
}

In this class, get method returns a Promise, which resolves with DataType[] array, and rejects with Error type.

Compiling this code, I'm getting this error:

Type 'Error | DataType[]' is not assignable to type 'DataType'. Type 'Error' is not assignable to type 'DataType'.

I'm using TypeScript version 2.4.2. I'm sure this started happening after TypeScript upgrade, which made types checks more strict.

I want to know how to handle rejection with different type in newest TypeScript. Are there different practices for doing this?

Update: I've found a corresponding bug report, not solved yet https://github.com/Microsoft/TypeScript/issues/7588

UPDATE

I've created a repo demonstrating the problem, with two commits. First commit uses <TypeResolve | TypeReject> approach, second uses <TypeResolved> only. Both commits seem to not compile in real life.

Dan
  • 55,715
  • 40
  • 116
  • 154
  • The generic type constraint for promises only refers to the `resolve` type. The `reject` type is always `any`. – Nitzan Tomer Aug 13 '17 at 08:09
  • @NitzanTomer it seems to me you are not right. Typescript expects `reject` type to be the same as `resolve` type – Dan Aug 13 '17 at 09:06
  • No, it does not. The reject type is always `any`, regardless of the resolve type. When you say `Promise` then only the resolve type is `string`, the reject type can be anything (`any`) – Nitzan Tomer Aug 13 '17 at 09:21
  • You don't want `Promise` you just want `Promise` – Ben Aug 13 '17 at 09:24
  • @NitzanTomer @Ben I've created a repo where I have put code that does not compile in any way, with ` | Error` or without it. https://github.com/easy-one/promise_typescript – Dan Aug 13 '17 at 11:03
  • That's way too much code to go through. Please reproduce the problem in playground, that would be the best. – Nitzan Tomer Aug 13 '17 at 11:07

1 Answers1

6

The type parameter for Promise is only the type for .resolve, not for .reject. The type for .reject is always any, because the type cannot be known at compile time. One of the reasons for this is that async functions, which return promises, could potentially reject their promises with any exception.

You should write Promise<DataType[]> instead, and check the error type at runtime where you handle errors.

w0rp
  • 676
  • 7
  • 10
  • I may mistake, but Typescript throws an exception in my case. I hope this is a bug they will fix – Dan Aug 13 '17 at 17:06