Skip to content
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

Functions are compatible with ArrayLike<any> #18757

Closed
cartant opened this issue Sep 26, 2017 · 5 comments · Fixed by #41660
Closed

Functions are compatible with ArrayLike<any> #18757

cartant opened this issue Sep 26, 2017 · 5 comments · Fixed by #41660
Assignees
Labels
Breaking Change Would introduce errors in existing code Committed The team has roadmapped this issue Effort: Moderate Requires experience with the TypeScript codebase, but feasible. Harder than "Effort: Casual". Fix Available A PR has been opened for this issue Suggestion An idea for TypeScript

Comments

@cartant
Copy link

cartant commented Sep 26, 2017

TypeScript Version: 2.5.2

Code

function func() {}
const array: ArrayLike<any> = func;

See this TypeScript Playground example.

Expected behavior:

I'd have expected an error to be effected.

Actual behavior:

No error is effected if the type ArrayLike<any> is specified. It seems the absence of an index signature is not a consideration in this situation.

If the any is changed to, say, string an error is effected:

Index signature is missing in type '() => void'.
@cartant
Copy link
Author

cartant commented Sep 27, 2017

Essentially, this issue is a question: how are index signatures used when determining compatibility?

With functions, the index signature appears to be considered only if the signature's value type is not any:

// OK:
const a = () => {};
const b: { [n: number]: any } = a;

// ERROR: Index signature is missing in type '() => void'.
const c = () => {};
const d: { [n: number]: string } = c;

However, with interfaces, the index signature appears to be considered only if it is present:

// OK:
const e: { length: number } = { length: 0 };
const f: { [n: number]: any } = e;

// OK:
const g: { length: number } = { length: 0 };
const h: { [n: number]: string } = g;

// ERROR: Index signatures are incompatible.
const i: { length: number, [n: number]: number } = { length: 0 };
const j: { [n: number]: string } = i;

Searching has not yielded any answer as to what the expected behaviour is. And the considering of functions to be compatible with ArrayLike<any> is problematic with RxJS, as it results in projection functions being considered compatible with ObservableInput<any>.

@RyanCavanaugh RyanCavanaugh added In Discussion Not yet reached consensus Suggestion An idea for TypeScript labels Sep 27, 2017
@RyanCavanaugh
Copy link
Member

RyanCavanaugh commented Sep 27, 2017

The real culprit is the length property. ArrayLike specifies an index signature and a length; all functions do have a length property. The index signature doesn't match, except when the target index signature's type is any. This a somewhat ad-hoc rule based on the observation that { [s: string]: any } is effectively indistinguishable from the any type in TypeScript, so all types can match against that constraint without having an explicitly declared indexer.

We can explore backing out the special rule about any-targeted index signatures to only apply to string index signatures rather than number index signatures since the latter seems like an oversight at this point. But it'll be a breaking change and we'll have to make sure there aren't unintended side effects

@cartant
Copy link
Author

cartant commented Sep 27, 2017

Thanks. I'd guessed that there's an ad-hoc rule regarding { [s: string]: any } in there somewhere.

I'm curious as to why the seemingly-similar interface scenario does not effect an error:

const g: { length: number } = { length: 0 };
const h: { [n: number]: string } = g;

Is there an explanation for what appears to be differing behaviour?

@RyanCavanaugh RyanCavanaugh added Committed The team has roadmapped this issue and removed In Discussion Not yet reached consensus labels Oct 10, 2017
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 2.7 milestone Oct 10, 2017
@RyanCavanaugh
Copy link
Member

@sandersn we'd like to see what happens in RWC if we restrict the "any signature means whatever" behavior to string signatures only

@benlesh
Copy link

benlesh commented Feb 10, 2021

Any progress on this? We're still hitting it

@DanielRosenwasser DanielRosenwasser added the Breaking Change Would introduce errors in existing code label Feb 26, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Breaking Change Would introduce errors in existing code Committed The team has roadmapped this issue Effort: Moderate Requires experience with the TypeScript codebase, but feasible. Harder than "Effort: Casual". Fix Available A PR has been opened for this issue Suggestion An idea for TypeScript
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants