Typescript: Type assertion error should say something about assertion rule

Created on 16 Aug 2016  路  8Comments  路  Source: microsoft/TypeScript

TypeScript Version: master branch

Code

interface Foo {
    bug(): PromiseLike<number>;
    bar(): void;
}

var foo = {
    bug: () => new Promise<number>((resolve, reject) => { })
} as Foo
// Type '{ bug: () => Promise<number>; }' cannot be converted to type 'Foo'.
//   Property 'bar' is missing in type '{ bug: () => Promise<number>; }'.

Expected behavior:

Type assertion should work here. The error message should say about the assertion rule.

Error Messages Suggestion good first issue help wanted

Most helpful comment

While "assert" reflects the name of the syntactic form ("type assertions"), I wonder if "treat ... as" is more understandable.

Cannot treat a value of type 'T' as type 'U'. Neither type is assignable to the other.

All 8 comments

As I understand it, type assertions require one of the types to be assignable to the other, either way. In your example, neither the foo value or the Foo type are assignable to the other, so the type assertion fails.

To make that clearer, here are the equivalent types and related assignments:

interface Foo {
    bug(): PromiseLike<number>;
    bar(): void;
}

interface Baz { // this is the type of `foo` in the OP example
  bug(): Promise<number>;
}

var foo: Foo;
var baz: Baz;

foo = baz; // ERROR: 'Baz' is not assignable to 'Foo'. Property 'bar' missing in type 'Baz'...
baz = foo; // ERROR: 'Foo' is not assignable to 'Baz'... 'PromiseLike<>' is not assignable to 'Promise<>'...

Type assertions in the spec

@yortus Ah thanks, that is understandable. But then I think the error message here is confusing as it does not say anything about the type assertion rule.

I don't think every error message should recite the relevant spec section, but we do see this reported fairly often.

Would something like this be useful?

Cannot assert from 'T' to 'U'. Neither type is assignable to the other.
  Cannot convert 'T' to 'U'
    Property 'p' is missing in 'T'

That is helpful :D

While "assert" reflects the name of the syntactic form ("type assertions"), I wonder if "treat ... as" is more understandable.

Cannot treat a value of type 'T' as type 'U'. Neither type is assignable to the other.

For type assertion error, I usually found that the fix suggestions ("Property 'p' is missing in 'T'") misleading.

By definition, if types T and U are not either-way-assignable, there must be
(1) some properies only exists in T and some properies only exists in U, or
(2) same properies with types that are not either-way-assignable, or
(3) some properies only exists in T and some properies in T which are not assignable to same properies in U.

The actual fix for type assertion error may be done on T or U, or both, by adding or removing propertys, or changing the assertion itself, but the compiler only suggests one approach.

I suggest not providing fix suggestions, instead just pointing out the properties in trouble.

  1. If some properies only exists in T and some properies only exists in U, the error messsage could contain:

    "Properties only in T: x, y, z; properties only in U: a, b, c."

  2. Else if same properies with types that are not either-way-assignable, the error messsage could contain:

    "Property 'foo' has types not assignable either way. (Recusively explain why types of 'foo' are not either-way-assignable...)"

  3. Else if some properies only exists in T and some properies in T is not assignable to same properies in U, the error messsage could contain:

    "Properties only in T: x, y, z; property 'a' in T with type V is not assignable to to same property in U with type W. (Recusively explain why V is not assignable to W.)"

So the error message of the first test case in this thread could be:

Cannot treat a value of type '__T1__ ({ bug: () => Promise<number>; })' as type 'Foo'.
Neither type is assignable to the other.
  Property only in 'Foo': 'bar'.
  Property 'bug' in 'Foo' is not assignable to to same property in '__T1__'.
    Type 'PromiseLike<number>' is not assignable to type 'Promise<number>'.
        Property 'catch' is missing in type 'PromiseLike<number>'.

I also suggest that the compiler assigning a random type name(e.g. __T1__) to each anonymous type, to make the error message more concise.

I believe this has been addressed by #25541.

I can confirm that the message has been updated:

Conversion of type '{ bug: () => Promise<number>; }' to type 'Foo' may be a mistake
because neither type sufficiently overlaps with the other. If this was intentional, convert
the expression to 'unknown' first.
  Property 'bar' is missing in type '{ bug: () => Promise<number>; }'.

I'll close this issue, feel free to open a new one (and link back) to give more suggestions. 馃憤

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jbondc picture jbondc  路  3Comments

dlaberge picture dlaberge  路  3Comments

zhuravlikjb picture zhuravlikjb  路  3Comments

DanielRosenwasser picture DanielRosenwasser  路  3Comments

Roam-Cooper picture Roam-Cooper  路  3Comments