You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
type parameter with a constraint on an indexed type cannot be indexed #31726
Expected behavior:
you should be able to index the e function parameter, as was the behavior before 3.5. Actual behavior:
in typescript 3.5 this code results in a Type '"a"' cannot be used to index type 'E' error.
I understand this is (probably) caused by this change #30637
But since I'm adding a constraint on the type parameter I feel like this still keeps type safety and should be a bug.
(This feels like such an obvious use case I figured there has to be an issue already open or closed and I was really hesitant on opening this issue, but I couldn't find any. If it's a duplicate, sorry...)
Hmm, this is an interesting case. Subtyping (extends) is essentially a question of substitutability. Structural typing requires that a subtype have at least the properties of the base type, so the only things substitutable in place of { [key: string]: string } would necessarily also have a [key: string] index signature. So I would consider the error Type '"a"' cannot be used to index type 'E' to be a bug.
The interesting thing is that the assignment is unsound: We don't know that E doesn't have a more specific type for its index signature than string. [key: string]: "foo" is perfectly fine to use in place of [key: string]: string. But that's definitely not the issue here, since TS doesn't typically enforce contravariance anyway:
functionfoo<Eextends{pig: string}>(e: E){e.pig="oh no";// this checks out}letx={pig: "it eats people"}asconst;foo(x);
Hmm, #30769 was a broader change than I realized. Is there a case where the code above (or something like it) wouldn’t be typesafe? You can’t remove properties from a subtype (otherwise it’s not a subtype anymore), so AFAICT E extends { [x: string]: string } could only be a type with a similar catch-all signature.
AFAICT E extends { [x: string]: string } could only be a type with a similar catch-all signature.
That's not the case. It only enforces that all known properties (if any) of the parameter are of type string. The following calls are valid using the declaration of the OP:
Hmm, but you can’t actually index the type with arbitrary keys then, can you? So the function would also have to accept one or more keyof E to be useful, I’m thinking.
Activity
fatcerberus commentedon Jun 2, 2019
Hmm, this is an interesting case. Subtyping (
extends) is essentially a question of substitutability. Structural typing requires that a subtype have at least the properties of the base type, so the only things substitutable in place of{ [key: string]: string }would necessarily also have a[key: string]index signature. So I would consider the errorType '"a"' cannot be used to index type 'E'to be a bug.The interesting thing is that the assignment is unsound: We don't know that
Edoesn't have a more specific type for its index signature thanstring.[key: string]: "foo"is perfectly fine to use in place of[key: string]: string. But that's definitely not the issue here, since TS doesn't typically enforce contravariance anyway:ajafff commentedon Jun 2, 2019
This is working as intended. This behavior was introduced by #30769
fatcerberus commentedon Jun 2, 2019
Hmm, #30769 was a broader change than I realized. Is there a case where the code above (or something like it) wouldn’t be typesafe? You can’t remove properties from a subtype (otherwise it’s not a subtype anymore), so AFAICT
E extends { [x: string]: string }could only be a type with a similar catch-all signature.ajafff commentedon Jun 2, 2019
That's not the case. It only enforces that all known properties (if any) of the parameter are of type
string. The following calls are valid using the declaration of the OP:fatcerberus commentedon Jun 2, 2019
Hmm, but you can’t actually index the type with arbitrary keys then, can you? So the function would also have to accept one or more
keyof Eto be useful, I’m thinking.Thanks for the explanation!
sthuck commentedon Jun 2, 2019
thank you guys for helping and referring me to the original PR, this issue #31661 seems to be the same and has some more discussion.