Skip to content

Type assertion error should say something about assertion rule #10360

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
saschanaz opened this issue Aug 16, 2016 · 8 comments
Closed

Type assertion error should say something about assertion rule #10360

saschanaz opened this issue Aug 16, 2016 · 8 comments
Labels
Domain: Error Messages The issue relates to error messaging Good First Issue Well scoped, documented and has the green light Help Wanted You can do this Suggestion An idea for TypeScript

Comments

@saschanaz
Copy link
Contributor

saschanaz commented Aug 16, 2016

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.

@saschanaz saschanaz changed the title TS incorrectly requires full interface implemention TS incorrectly requires full interface implemention for type assertion Aug 16, 2016
@saschanaz saschanaz changed the title TS incorrectly requires full interface implemention for type assertion TS requires full interface implemention for type assertion Aug 16, 2016
@saschanaz saschanaz changed the title TS requires full interface implemention for type assertion Type assertion requires full interface implemention Aug 16, 2016
@yortus
Copy link
Contributor

yortus commented Aug 16, 2016

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

@saschanaz
Copy link
Contributor Author

@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.

@saschanaz saschanaz changed the title Type assertion requires full interface implemention Type assertion error should say something about assertion rule Aug 16, 2016
@RyanCavanaugh RyanCavanaugh added Suggestion An idea for TypeScript Needs Proposal This issue needs a plan that clarifies the finer details of how it could be implemented. labels Aug 16, 2016
@RyanCavanaugh
Copy link
Member

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'

@saschanaz
Copy link
Contributor Author

That is helpful :D

@RyanCavanaugh RyanCavanaugh added Help Wanted You can do this and removed Needs Proposal This issue needs a plan that clarifies the finer details of how it could be implemented. labels Aug 16, 2016
@RyanCavanaugh RyanCavanaugh added this to the Community milestone Aug 16, 2016
@RyanCavanaugh RyanCavanaugh added the Good First Issue Well scoped, documented and has the green light label Aug 16, 2016
@DanielRosenwasser DanielRosenwasser added the Domain: Error Messages The issue relates to error messaging label Aug 21, 2016
@DanielRosenwasser
Copy link
Member

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.

@duanyao
Copy link

duanyao commented Dec 16, 2016

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.

@mattmccutchen
Copy link
Contributor

I believe this has been addressed by #25541.

@saschanaz
Copy link
Contributor Author

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. 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Domain: Error Messages The issue relates to error messaging Good First Issue Well scoped, documented and has the green light Help Wanted You can do this Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

6 participants