-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Enums, string/number types of interfaces/classes cannot be used as index signatures #37448
Comments
Just pointing out that in your example the type is not |
Sorry I was being rough... you’re correct |
@RyanCavanaugh I understand the point you're making. I already been commenting each line, and it's making more problems than it solves. As trivial as that sounds, having a live type reference with fast travel greatly enhances readability, it also will error if that property no longer exists/gets changed, which would make refactoring much safer. But it would be a shame to not allow SOME way of allowing this to take place. So the solution may be some sort of alternative syntax to indicate that type safety isn't being provided, you're just casting in the index to show this? Isn't this really just a question of syntax if my original suggestion hits the wall you're describing? Some ideas:
|
(Hmm, I'm seeing a comment in my email that is not present here in GitHub... I'm responding to that.) Although I'd like to see type aliases being allowed as index signatures, it's obviously up to the TypeScript's team discretion, so please don't take this comment as demanding that the feature be added. However, there's something I don't understand yet, that someone might be willing to clear up.
The argument against type aliases as index signatures, as I understand it, comes down to "it looks like we're enforcing a type there, but we're not - any string is valid, so allowing type aliases as index signatures would be misleading". I get that point. However, what I don't get, is: is that not an argument against having type aliases in general? For example:
Does the argument not hold there as well? We pretend that |
@Vinnl This is the exact point I made here #1778 (comment) The official response to which was
But that point has never been addressed and describes exactly what is wanted here. This addition would infer no safety beyond exactly what the language already does. The argument that it increases confusion does not hold water because this addresses a language inconsistency. I've also been wondering who the others in the plural "we've" are and why they have not spoken. This is marked as |
This issue has gone the same route as the last one. Solid points are being made and it goes nowhere. @RyanCavanaugh is the official Typescript team recommendation for this issue to just add comments everywhere? |
@RyanCavanaugh I also second removing the 'Awaiting more feedback', I'm not sure how much more feedback you need for the point to be driven home. In issue #1778 and in this one there are valid points being made, and the response has been to just ignore them and abandon the issue. Is that what's happening here? Again? |
We, the compiler team, get hundreds of comments every day on this repos issues. It's often much easier to let one person respond when they are closer to the domain. We already have to pick our battles in these issues to actually get work done, and mix that with people being less available from COVID19 and it's difficult to feel any progress on the language. For example, I used about 45m on just writing this tiny 3 paragraph reply. I get that this issue is something close to your heart, but the team has commented on this issue multiple times with the same consistent opinion through the years in the original thread. In my own OSS, I usually recommend that if someone is this passionate about a feature they should look at implementing it to try and better understand the constraints of the system. Maybe try give this a shot and have a better chance of coming at it from. language maintainers perspective too? |
I appreciate that. I don’t have the skill for the time to contribute to this in a competent way, I wish I did. But this feels like a repeat of what occurred last issue. And it’s a frustrating experience because I don’t necessarily want an improvement to TypeScript on my command done overnight, but a concise and clear answer that directly addresses concerns being raised and acknowledges there’s an actual problem here. I’m guessing at this point that the ‘official’ stance is that I have to make comments. I’ve already been doing that and will live with it... thanks for your time, I do appreciate it. |
We use interfaces derived from
Now we can write functions that consume these types, instead of plain strings, and we get a compile error if we mix them up. It would be amazing if I could say
... but I cannot. The workarounds are to convert these types back and forth to strings whenver using indexes, or to use Anything that could add support for using any |
As a workaround I've been using a Using @jamietre's case as an example: type Reports = {
[key: ReportId]: Report
} can be type Reports = Record<ReportId, Report>; |
The |
Just jumping on the bandwagon in support of this feature. It would add a great deal of clarity. |
Throwing in my support for this. I was attempting to use |
Looking forward to this issue being resolved! I do not understand the reasoning from #1778 that this would "create the implication that you're making different kinds of index signature". If the type aliasing was resolved and checked by the compiler, there would be no implications, it would either compile and one would be able to hover over it in an IDE to check the resolved type, or error and let one know that the type did not resolve to an allowed type. Much thanks to @alecf for the temporary workaround for the need to add a comment explaining the type relation. |
In the spirit of the "Awaiting More Feedback" tag - I came across this exact situation and was very confused / surprised to find I wasn't able to use an alias to describe the key. I now have comments in the code base explaining what could otherwise be more accurately described by a type alias. More cognitive overload for the next guy. I think Ryan's point here (from #1778 (comment)):
is missing the key ingredient - that, for future maintainers and reviewers, it is in fact MORE confusing that we can't alias the type, when the rest of the language allows us to use aliases for virtually everything and the alternative is an extra comment linking to these issues. Instead we have to read comments and GitHub issue threads that basically boil down to "in this specific instance we don't want to improve the typing of your objects because javascript is the underlying and you could hypothetically monkeypatch it elsewhere" (which could likely be detected in By way of example, which is more confusing to the next person to come across this code?
or
Furthermore downstream consumers don't know that this object's keys actually refer to something specific and are not intended to be arbitrary. That's pretty confusing. |
@zacksinclair exceptional rebuttal 🍺 |
I'd be interested if @ahejlsberg has any input on the topic. |
This started working in TS 4.4: class User {id: string = '4'}
class Post {id: string = 'hello'}
const postToUsers: {[key: Post['id']]: User} = {} Digging deeper, the new index signature features are in the 4.4 release notes. |
Thanks for pointing this out. This does solve the initial issue raised in #1778. It's unfortunate it took this 6 year road and had the responses it got. |
Indeed, this issue was fixed by #44512 which is included in TS 4.4. Also, in TS 4.4 and later it is possible to have index signatures for tagged primitive types, for example: type Id = string & { __tag: 'id '};
type Rec = Record<Id, number>;
declare const s: string;
declare const id: Id;
declare const rec: Rec;
rec[s] = 1; // Error
rec[id] = 1; // Ok |
YEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEESSSSSSSSSSSSSSSSSSSSSSSSSS ! ♥ |
Due to unresponsiveness and a highly unsatisfactory outcome on issue #1778, I want to raise a fresh issue so I can get a clear and final outcome. I don't mind if it's another no (actually I would because it makes zero sense), but if it's a no, I would like something that wasn't provided in the referenced issue: a CLEAR solution to this problem.
So let's recap with some basics:
enum
:number
, orstring
.string
ornumber
, or contain a property that is astring
ornumber
string
andnumber
It naturally follows that index signatures should be able to be aliased, purely by observing the above facts alone.
But let's step into a practical scenario.
It's common to make the equivalent of a hashmap or lookup map, whether it be for the developer's convenience, or for performance reasons. Either way, it's almost always the case in my experience that the indexes of these hash maps correspond to a type expressed elsewhere in the codebase, and aren't just an arbitrary/random index value.
e.g.
public templateElementHashMap: { [s: string]: TemplateElement } = {};
This shows an incomplete context, as the
string
type is always going to be thehash
property in the class below:Therefore, the truest expression would be this:
public templateElementHashMap: { [s: TemplateElement['hash']]: TemplateElement } = {};
This provides full context to the developer, quick travel to the type of interest, and as long as
TemplateElement['hash']
isstring
ornumber
, the above statement is 100% correct, and does not break any rules regarding type consistency. It's a win/win, and clearly a large improvement.Instead right now, I have many lines where the index signature is just a
string
property, and it's become a pain to remember which hash map relates to which data I'm using it for. And quite often, I'm wasting time poking around trying to remember which index derives from which type.So I'm going to ask again: what is the solution? To me there are only two:
I've poured a fair amount of my time providing feedback and input for TypeScript since its early days, and only ask this is treated with the promptness and attention that I have received in the past, and not closed prematurely like the other issue.
So please can I receive a clear and concise workaround, or (preferably) the acknowledgement that something actually is inadequate with the design around this and I'm not just going insane, along with the many others who have expressed the same problem.
The text was updated successfully, but these errors were encountered: