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

Index signature pointing to any is too relaxed #24083

Closed
inad9300 opened this issue May 12, 2018 · 12 comments
Closed

Index signature pointing to any is too relaxed #24083

inad9300 opened this issue May 12, 2018 · 12 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@inad9300
Copy link

How come this code fails...

type T = {
    [p: string]: string
}

function f(t: T) { }

f([]) // Index signature is missing in type 'undefined[]'.

...and even this one...

type T<S> = {
    [p: string]: S
}

function f<S>(t: T<S>) { }

f([]) // Index signature is missing in type 'undefined[]'.

...but this one doesn't?

type T = {
    [p: string]: any
}

function f(t: T) { }

f([])

I'm sorry if this has been pointed out before; it's difficult for me to look for related issues.

@basarat
Copy link
Contributor

basarat commented May 13, 2018

Works as expected.

Reason:

This errors because undefined is not assignable to string:

type T = {
    [p: string]: string
}

function f(t: T) { }

f([]) // Index signature is missing in type 'undefined[]'. 

This works because undefined is assignable to any:

type T = {
    [p: string]: any
}

function f(t: T) { }

f([])

More

[p:string]: any is a mostly useless index signatures. It is essentially just as useful as a raw any, just thinly guised as an index signature.

@mhegazy mhegazy added the Question An issue which isn't directly actionable in code label May 14, 2018
@inad9300
Copy link
Author

If the reason why your second snippet works really was that "undefined is assignable to any", then this should also work, since undefined is assignable to undefined (or void), but it doesn't:

type T = {
    [p: string]: undefined
    // Or: [p: string]: void
}

function f(t: T) { }

f([])

TypeScript error says "index signature is missing". If an index signature is expected, however it is defined, and a type is provided with no index signature, it should fail. I don't understand how anyone could expect a different behaviour. We already have any to mean "any", we don't need more obscure synonyms for it.

@RyanCavanaugh
Copy link
Member

RyanCavanaugh commented May 21, 2018

If an index signature is expected, however it is defined, and a type is provided with no index signature, it should fail. I don't understand how anyone could expect a different behaviour.

This used to be the behavior and we intentionally changed it; see #4074. There's a very long discussion leading up to that in #3823. See also #3823 (comment)

@inad9300
Copy link
Author

It is unclear to me that the change was in the right direction. I don't see what benefit rendering [key: string]: any useless brings. Also, if I understand its current meaning, it is saying something like "and any other property you wish", which is a behavior already covered by extends. Thus, these two functions are now equivalent:

function f(o: { n: number, [key: string]: any }) { }
function g<O extends { n: number }>(o: O) { }

With its prior meaning you could at least force a type to simply define an index signature, and restrict the type of its key. (In this sense, I think it would have made sense to allow optional index signatures, with the meaning "if an index signature is present, it must comply with such and such restriction".)

There is another point which at the moment I'm not seeing clearly -- how can one define a function which accepts a plain object?

@RyanCavanaugh
Copy link
Member

There is another point which at the moment I'm not seeing clearly -- how can one define a function which accepts a plain object?

function f(x: object) {

@inad9300
Copy link
Author

f([])

@RyanCavanaugh
Copy link
Member

Correct, an array is a subtype of object. typeof [] === "object", etc.

@inad9300
Copy link
Author

Yes, but I was asking for a plain object. As in $.isPlainObject(), or as in _.isPlainObject(). Essentially --I used to think-- as in {[key: string]: any}... My point being, if there is no alternative way of expressing this, it looks like a big loss to me, again with no clear benefit.

@typescript-bot
Copy link
Collaborator

Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.

@inad9300
Copy link
Author

Just to come to a conclusion, there is no way in TypeScript to express the idea of a plain object, and you will not make stricter the index signatures again. Is that correct?

@RyanCavanaugh
Copy link
Member

object is object; you could use something like this if you really feel that Arrays aren't actually objects:

function f(x: object & { push?: never }) {
}

f({}); // OK
f([]); // Error

We do not currently intend to change anything around index signatures

@inad9300
Copy link
Author

Not sure why you insist on object. In any case, all I'm trying to say again is that it is useful to have the ability to force the presence of index signatures and the type of their key. If having an index signature for which you don't see a practical usage is annoying, as was the original argument by @joewood and @ahejlsberg in #3823 (comment), then just don't use it!

But OK, I won't insist more... I guess I'm still trying to value correctness over convenience, but the majority wants it otherwise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

5 participants