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
string not assignable to Record with specific number key #59489
An error occurs because a string is not assignable to a record type with an index type that is a specific number. This seems wrong because string are generally indexable by numbers. And array types are indexable by specific number types.
🙂 Expected behavior
No error when trying to assign a string to a record type where the index is a specific number.
Additional information about the issue
I bumped into this when trying to implement a generic comparator function like compareBy(0)('abc', '123') === 1.
This sort of falls out of the inference rules and it's not super clear which rule would need to change here that wouldn't break something else much more badly.
Since this can be written more straightforwardly this way, I wouldn't really consider this a bug
It's a little awkward to try to figure out the intended semantics here. It seems like you'd want compareBy("x") to only accept things with a declared { x: something }, but then for 0, strings don't have a declared 0 property (and indeed might be zero-length), so rejecting "" because it doesn't have { 0: something } is just as correct as the rejection of "x".
It seems like you'd want compareBy("x") to only accept things with a declared { x: something },
compareBy(0) could also be used for comparing lists by the first element. I admit indexing strings is a little edgy, but I think there is value in having this work generically.
so rejecting "" because it doesn't have { 0: something } is just as correct as the rejection of "x"
But the error occurs even if you change the string type to a specific non-zero-length string.
Also I think we should expect strings and arrays to be consistent in this regard.
functionhasZeroKey(x: Record<0,any>){}functionhasNumberKey(x: Record<number,any>){}hasZeroKey("abc");// errorhasNumberKey("abc");// okhasZeroKey([1,2,3]);// okhasNumberKey([1,2,3]);// ok
It is consistent, it's just that strings don't get any contextual tuple-like inference the way arrays do (it's unclear where that would ever be useful):
There doesn't need to be tuple-like inference. Typescript optimistically assumes that indexing an unknown-length array will yield an element. It should also assume that indexing a string yields a string. In fact string[number] or string[0] does equal string, but it just doesn't allow you to express that rule in terms of a record type. But you can with arrays. So that seems definitely inconsistent to me.
functionhasZeroKey(x: Record<0,any>){}hasZeroKey([1,2,3]);// ok
is that the [1, 2, 3] literal gets inferred to be a tuple (which has declared 0, 1, 2 properties). Without that tuple inference, it's just an object with a numeric index signature, and it's intentional that an index signature isn't allowed to satisfy a declared property.
Activity
RyanCavanaugh commentedon Jul 31, 2024
This sort of falls out of the inference rules and it's not super clear which rule would need to change here that wouldn't break something else much more badly.
Since this can be written more straightforwardly this way, I wouldn't really consider this a bug
camsteffen commentedon Jul 31, 2024
Here's another example, closer to what I was trying to do:
RyanCavanaugh commentedon Jul 31, 2024
It's a little awkward to try to figure out the intended semantics here. It seems like you'd want
compareBy("x")to only accept things with a declared{ x: something }, but then for0, strings don't have a declared0property (and indeed might be zero-length), so rejecting""because it doesn't have{ 0: something }is just as correct as the rejection of"x".camsteffen commentedon Jul 31, 2024
compareBy(0)could also be used for comparing lists by the first element. I admit indexing strings is a little edgy, but I think there is value in having this work generically.But the error occurs even if you change the string type to a specific non-zero-length string.
Also I think we should expect strings and arrays to be consistent in this regard.
RyanCavanaugh commentedon Aug 1, 2024
It is consistent, it's just that strings don't get any contextual tuple-like inference the way arrays do (it's unclear where that would ever be useful):
camsteffen commentedon Aug 2, 2024
There doesn't need to be tuple-like inference. Typescript optimistically assumes that indexing an unknown-length array will yield an element. It should also assume that indexing a string yields a string. In fact
string[number]orstring[0]does equalstring, but it just doesn't allow you to express that rule in terms of a record type. But you can with arrays. So that seems definitely inconsistent to me.camsteffen commentedon Aug 2, 2024
I found a workaround for my
compareByuse case.RyanCavanaugh commentedon Aug 2, 2024
The thing that allows this
is that the
[1, 2, 3]literal gets inferred to be a tuple (which has declared0,1,2properties). Without that tuple inference, it's just an object with a numeric index signature, and it's intentional that an index signature isn't allowed to satisfy a declared property.camsteffen commentedon Aug 2, 2024
Hmm I see. I thought I saw it working with
number[]but it doesn't.typescript-bot commentedon Aug 5, 2024
This issue has been marked as "Not a Defect" and has seen no recent activity. It has been automatically closed for house-keeping purposes.