Repository navigation
T[keyof T] should be never for T={} #22042
Description
Activity
- changed the title
[-]T[keyof T] should be valid for T={}[/-][+]T[keyof T] should be never for T={}[/+]on Feb 20, 2018 sandersn commented
on Feb 20, 2018 MemberMore actionsNote that adding
if (indexType.flags & TypeFlags.Never) { return neverType; }
in
getPropertyTypeForIndexTypedoes not cause any tests to fail, but causes the example to pass. I think that means our test coverage is pretty bad for index types. I'll try compiling the RWC or user tests to see if the types change in some react projects.Reacted by Daniel Rosenwasser and Troy Gerwiensandersn commented
on Feb 20, 2018 MemberMore actionsThere is one break in Large Microsoft Project 199 (the one with a blue logo. no, the other one):
// NOT THE ACTUAL CODE import _ = require('lodash'); interface A { m(): void; } const xs = { [n: number]: A } = {}; // other code ... function all() { _.each(xs, x => x.m()); }
x's inferred type isnevernow where it was previouslyany. Here's an altered example that doesn't depend on lodash:type A = { p: number } type It<T, U> = (value: T[keyof T]) => U; declare function _each<T>(collection: T, iteratee: It<T, any>): void; function allofem(xs: { [n: number]: A }) { _each(xs, x => x.p) }
Reacted by Daniel Rosenwasser and falsandtruThanks for looking at it Nathan Shively-Sanders (@sandersn). Pity it's a breaking change, although that must be incredible rare.
So do you think this is a bug or a suggestion? I think it's a bug, since
T[never]is implicitly covered by the definition in #11929 but doesn't work as specified there.- addedSuggestionAn idea for TypeScriptAn idea for TypeScriptIn DiscussionNot yet reached consensusNot yet reached consensus
on Feb 21, 2018 sandersn commented
on Feb 21, 2018 MemberMore actionsTroy Gerwien (@yortus) I don't think it's clear whether it's a bug or a suggestion. I'm leaning toward bug, but either way we need to look at the pros and cons of fixing it.
Re:rarity. I'm not sure about incredibly rare — lodash had 2.5 million downloads yesterday and
@types/lodashhad over 100,000. Anybody who calls_.eachwith a number-indexed type will get this bad behaviour. (I think they probably wanted to call theT[]overload in the first place, but it may exhibit the same behaviour).Of course we can probably fix lodash to work around any changes that we end up making. The question is whether other code will run into it.
Nathan Shively-Sanders (@sandersn) right - actually I see that
T[keyof T]comes up 90 times across the lodash definitions.But isn't this showing up a different problem with
keyof? Why doeskeyof {[n: number]: any}eveluate tonever? Shouldn't it bestring? The numeric indexer is just telling TypeScript that the objects keys are constrained to numbers only, but they are still effectively all string-typed keys.Since
keyof {1: 1}is"1"andkeyof {1:1, 2:2, ...99: 99}is"1"|"2"|..|"99", then by extensionkeyof {[n: number]: number}should bestringright? At least it should not benever, since we are telling TypeScript there are string keys in there.If
keyofwas fixed for numeric indexers, then the_.eachexample above would work properly regardless of thisT[K]issue.I opened a new issue at #22105 regarding
keyof {[n: number]: any}.Nathan Shively-Sanders (@sandersn) everything works if you preserve the special handling of types with string/numeric indexers in
getPropertyTypeForIndexType(which are special cases according to #11929).If you handle the
T[never]case after the special handling for string/numberic indexers, then this change won't break things likelodashanymore, and things likeRequiredProps<{}>(#21988) will get better typing.Actually if done this way, wouldn't it be a strictly non-breaking change, since the only changed behaviour is for cases that are currently compile-time errors?
Troy Gerwien (@yortus) Thanks for the additional investigation. I'm heads down on Javascript work right now, but I'll come back to this when I have time, or if you want to submit the PR, that would work too.
Reacted by Troy GerwienHeads up I ran into this problem also, and based on everything you guys said it sounded pretty simple to fix so I created a PR at #22787.
RyanCavanaugh commented
on Mar 26, 2018 MemberMore actionsAnders Hejlsberg (@ahejlsberg) have a look at the associated PR?
- addedFixedA PR has been merged for this issueA PR has been merged for this issueand removedIn DiscussionNot yet reached consensusNot yet reached consensus
on Mar 27, 2018 - locked and limited conversation to collaborators
on Jul 25, 2018
TypeScript Version: 2.8.0-dev.20180216
Search Terms:
Code
Expected behavior:
A[keyof A]is a valid indexed access type that evaluated tonever.Actual behavior:
A[keyof A]is treated as an error, and evaluates toany(presumably due to compiler bailout).Related Issues:
#11929 describes indexed access types as follows:
In this case
K=neverandT={}, soKis assignable tokeyof T, soT[K]appears to be a valid type.The union of zero property keys is
never, as tsc shows withkeyof {} = never.So the result should be the union of zero property types, i.e. also
never.Consequences:
In more complex generics this leads to meaningful problems, e.g. in #21988 where
RequiredProps<{}>evalutes to{[x: string]: any}when it should be{}.