Skip to content

Array of tuple literal not assignable to iterable of tuple with --lib es2015 -t es5 #32761

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

Open
laughinghan opened this issue Aug 8, 2019 · 11 comments
Assignees
Labels
Needs Investigation This issue needs a team member to investigate its status.

Comments

@laughinghan
Copy link

laughinghan commented Aug 8, 2019

TypeScript Versions: 3.5.1, 3.5.3 (currently typescript@latest), 3.6.0-beta (currently typescript@beta), 3.6.0-dev.20190808 (currently typescript@next)

Search Terms:

Code

// Works:
declare function foo<T>(i: Iterable<T>): T
const x = foo([1]); // infers a: number

// Fails:
declare function bar<T, U>(j: Iterable<[T, U]>): [T, U]
const y = bar([[1, 'a']]);
//             ^^^^^^^^
//             Argument of type '(string | number)[][]' is not assignable to
//             parameter of type 'Iterable<[string | number, string | number]>'.

// workaround:
declare function qux<T, U>(j: Array<[T, U]> | Iterable<[T, U]>): [T, U]
const z = qux([[1, 'a']]); // infers z: [number, string]

Expected behavior: variable y is inferred to be of type [number, string] and parameter j is inferred to be of type Array<[number, string]>

Actual behavior: error TS2345: Argument of type '(string | number)[][]' is not assignable to parameter of type 'Iterable<[string | number, string | number]>'.

Playground Link

Related Issues: maybe #29311 ?

@dragomirtitian
Copy link
Contributor

Cloned repo, ran tsc .\hello.ts -target es2015, no error.

Are you sure you don't have another tsc installed on your system? Run a tsc- -v

@laughinghan
Copy link
Author

Are you able to reproduce the error with tsc --lib esnext hello.ts, as suggested in the README?

I am finding that -target es2015 makes the error go away. Thanks, that explains the difference from Playground; if -target is made to match the Playground "Target" option, then the behavior of tsc matches Playground exactly.

However, I'm targeting ES5 (and polyfilling ES2015 features). And the library I'm using, Facebook's ImmutableJS, presumably has to target a range of ES versions, so they want to reference Iterable in their type declaration: https://github.com/immutable-js/immutable-js/blob/master/type-definitions/Immutable.d.ts#L1420

Is this expected behavior with --lib?

@laughinghan laughinghan changed the title Tuple type inference fails on files but not in Playground Tuple type inference fails with --lib es2015 -t ES5 Aug 8, 2019
@RyanCavanaugh
Copy link
Member

If target is ES5 and you're polyfilling Symbol.iterator, then you should turn on downlevelIteration to cause arrays to appear to have the iterator symbol

@RyanCavanaugh RyanCavanaugh added the Question An issue which isn't directly actionable in code label Aug 8, 2019
@laughinghan
Copy link
Author

But that makes for...of loops much slower at runtime? This is a typings issue, I'm not going to sacrifice runtime performance to fix it.

It looks like adding Array<[K, V]> as an additional type overload besides Iterable<[K, V]> fixes the issue. I'll submit a PR to ImmutableJS. Thanks for all your help and the ultra-fast response time!

laughinghan added a commit to laughinghan/typescript-tuple-inference-testcase that referenced this issue Aug 8, 2019
@laughinghan
Copy link
Author

laughinghan commented Aug 8, 2019

@RyanCavanaugh Actually, I'm confused why --downlevelIteration matters. lib.es2015.iterable.d.ts declares a Symbol.iterator on Array: https://github.com/microsoft/TypeScript/blob/master/src/lib/es2015.iterable.d.ts#L40

So why isn't --lib es2015 sufficient to cause arrays to appear to have the iterator symbol?

The docs for --downlevelIteration only mention for..of, spread and destructuring, they don't mention anything about the iterator symbol either (Compiler Options).

@laughinghan
Copy link
Author

Actually no, this seems like an issue with type inference.

In most cases (not for..of, obviously), --lib es2015 causes Array<T> to be assignable to Iterable<T>, but not if a tuple type is involved; in some cases, the error message doesn't even mention incompatibility between Array and Iterable, it says:

Type '(string | number)[]' is not assignable to type '[string | number, string | number]'.

In this Playground Link, the first 4 examples here all show that Array<T> is normally assignable to Iterable<T>, the next 4 demonstrate the issue when a tuple type is involved.

Both --downlevelIteration and using Array<[T, U]> as an alternative to Iterable<[T, U]> do workaround the issue, though.

@laughinghan laughinghan reopened this Aug 9, 2019
laughinghan added a commit to laughinghan/immutable-js that referenced this issue Aug 10, 2019
When compiling TypeScript targeting ES5, if --downlevelIteration isn't
used, then arrays of tuples won't be considered assignable to iterables
of tuples, resulting in type errors when doing common things like
Map([['key', 'value']]):

microsoft/TypeScript#32761

--downlevelIteration hurts runtime performance of for..of loops on
arrays, but a type definition-only workaround is to explicitly include
arrays or array sof tuples in parameter types or function overloads.
@laughinghan laughinghan changed the title Tuple type inference fails with --lib es2015 -t ES5 Array<[T, U]> not assignable to Iterable<[T, U]> with --lib es2015 -t es5 Aug 10, 2019
@laughinghan laughinghan changed the title Array<[T, U]> not assignable to Iterable<[T, U]> with --lib es2015 -t es5 Array of tuple literal not assignable to iterable of tuple with --lib es2015 -t es5 Aug 10, 2019
@laughinghan
Copy link
Author

@RyanCavanaugh just updated title, code sample, and Playground link to succinctly illustrate that downlevelIteration should be unnecessary, since array literals are already assignable to iterables if the contents aren't tuples.

@typescript-bot
Copy link
Collaborator

This issue has been marked as 'Question' and has seen no recent activity. It has been automatically closed for house-keeping purposes. If you're still waiting on a response, questions are usually better suited to stackoverflow.

@laughinghan
Copy link
Author

@RyanCavanaugh Can you unmark this as a Question? I think the updated code sample succinctly illustrates that it's a bug

@RyanCavanaugh
Copy link
Member

Looking

@RyanCavanaugh RyanCavanaugh added Needs Investigation This issue needs a team member to investigate its status. and removed Question An issue which isn't directly actionable in code labels Aug 16, 2019
@RyanCavanaugh
Copy link
Member

@rbuckton can you explain what's happening? Bug?

@RyanCavanaugh RyanCavanaugh reopened this Aug 16, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs Investigation This issue needs a team member to investigate its status.
Projects
None yet
Development

No branches or pull requests

5 participants