Skip to content

Typecast to any in one array element affects other elements #26184

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
DanielSWolf opened this issue Aug 3, 2018 · 7 comments
Closed

Typecast to any in one array element affects other elements #26184

DanielSWolf opened this issue Aug 3, 2018 · 7 comments
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed

Comments

@DanielSWolf
Copy link

DanielSWolf commented Aug 3, 2018

TypeScript Version: 3.1.0-dev.20180803

Search Terms: any, object, array, "is not assignable to type"

Code

const x: Array<{ foo: number }> = [
  { foo: 'this is the wrong type' },
  { foo: 42 as any },
];

const y: Array<{ foo: number }> = [
  { foo: 'this is the wrong type' },
  { foo: 42 },
];

Expected behavior:

I expect two build errors: One for the assignment of x, one for y.

This is because both x and y are assigned values of the wrong type. In both cases, not all array elements contain a property foo of type number.

Actual behavior:

There is no build error for the assignment of x, only for the assignment of y. This is the build output:

➜  dev tsc any-test.ts
any-test.ts:6:7 - error TS2322: Type '({ foo: string; } | { foo: number; })[]' is not assignable to type '{ foo: number; }[]'.
  Type '{ foo: string; } | { foo: number; }' is not assignable to type '{ foo: number; }'.
    Type '{ foo: string; }' is not assignable to type '{ foo: number; }'.
      Types of property 'foo' are incompatible.
        Type 'string' is not assignable to type 'number'.

6 const y: Array<{ foo: number }> = [
        ~

In the assignment of x, the foo property of the second array element is converted to any. Rather than converting only this one value to any, TypeScript seems to convert the foo properties of all array elements to any.

Playground Link: Playground demo

Related Issues: none

@RyanCavanaugh RyanCavanaugh added the Design Limitation Constraints of the existing architecture prevent this from being fixed label Aug 3, 2018
@RyanCavanaugh
Copy link
Member

RyanCavanaugh commented Aug 3, 2018

The algorithm for checking the program works like this:

  • Is the initializer assignable to the declared type?
  • Let's figure out the type of the initializer
  • What the type of the initializer? It's an array of something. What is "something" ?
  • It's the union type of all the elements. What's the type of each element?
  • First element is {foo: string}, second element is {foo: any}
  • The union type {foo: string} | {foo: any} is subtype-reduced to {foo: any}
  • Is Array<{foo: any}> assignable to Array<{foo: number>}> ?
  • Yes
  • The program contains no errors

The net result is "wrong" but every individual step in that logic is right and can't really be changed without breaking something else (including being a breaking change in existing code). You can cast to never instead to get the "correct" result

@weswigham
Copy link
Member

@RyanCavanaugh Typechecking array literals as tuples (which we had mentioned elsewhere for other things) would actually solve this.

@RyanCavanaugh
Copy link
Member

RyanCavanaugh commented Aug 3, 2018

@weswigham in addition to being a breaking change, it still leaves problems like

var x = ["", 1 as any]; // presumably still widened to any[]?
var y: number[] = x;

@DanielSWolf
Copy link
Author

Would it be possible to treat literals differently if their target type is known in advance? Here are a few examples:

// Assignment to variable of known type
const foo: SomeType = [...];

// Function argument of known type
function foo(arg: SomeType);
foo([...]);

// Property of known type
const foo: { bar: number[] } = { bar: [...] };

I know that there are other languages that do this. But I have no idea whether that's feasible for TypeScript.

@RyanCavanaugh
Copy link
Member

We tried doing this - see #19541 - and ran into some architectural problems. We should try again, though

@DanielSWolf
Copy link
Author

@RyanCavanaugh Did you mean to close this issue, while marking the other (#32165) as a duplicate?

@chrisnojima
Copy link

I agree we should leave this one open, i closed mine.
Just to explain my use case. I'm importing several modules in a brownfield app and building an array of a known type. One of the modules hasn't been nicely typed so its value is any.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed
Projects
None yet
Development

No branches or pull requests

4 participants