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

Regression: IndexedAccess T[keyof T] is not assignable to anything #21368

Closed
ajafff opened this issue Jan 23, 2018 · 9 comments
Closed

Regression: IndexedAccess T[keyof T] is not assignable to anything #21368

ajafff opened this issue Jan 23, 2018 · 9 comments
Labels
Bug A bug in TypeScript Fixed A PR has been merged for this issue

Comments

@ajafff
Copy link
Contributor

ajafff commented Jan 23, 2018

TypeScript Version: 2.7.0-dev.20180123

Search Terms: indexed access, type parameter keyof

Code

interface I {
    foo: string;
}

declare function take<T>(p: T): void;

function fn<T extends I, K extends keyof T>(o: T, k: K) {
    take<string>(o[k]); // Argument of type 'T[K]' is not assignable to parameter of type 'string'.
    take<{} | null | undefined>(o[k]); // Type 'T[K]' is not assignable to type '{} | null | undefined'. Type 'T[K]' is not assignable to type '{}'.
    take<any>(o[k]); // this one works
}

Expected behavior:
Compiles without error. 2.7.0-rc allows all of the above, although the type of the indexed access is not correctly inferred, see #12991 (comment)

Actual behavior:
Error on the first two calls, see inline comments.

Playground Link:

Related Issues:
#12991

@ajafff ajafff changed the title IndexedAccess T[keyof T] is assignable to nothing Regression: IndexedAccess T[keyof T] is not assignable to anything Jan 25, 2018
@tomblind
Copy link

tomblind commented Feb 1, 2018

It looks like the first call to take shouldn't work, since there's no guarantee T[K] is a string. T could be an object that extends I and adds non-string properties.

But the second one should work. Previously, anything other than null and undefined could be assigned to the type '{}', but that doesn't seem to be the case anymore. Is this a bug, or by design?

@mhegazy
Copy link
Contributor

mhegazy commented Feb 1, 2018

Consider calling your function with:

interface A extends I { 
    bar: number;
}
declare var a: A;

fn(a, "bar");

@mhegazy mhegazy added the Working as Intended The behavior described is the intended behavior; this is not a bug label Feb 1, 2018
@tomblind
Copy link

tomblind commented Feb 1, 2018

So, just to confirm, the error in the following code is intended?

type unknown = {} | null | undefined;

function fn<T>(o: T, k: keyof T) {
    var v: unknown = o[k]; //Type 'T[keyof T]' is not assignable to type 'unknown'.
}

Is there something T[keyof T] could be that isn't assignable to {} | null | undefined ?

@mhegazy
Copy link
Contributor

mhegazy commented Feb 1, 2018

that is a special case really. the general case is that you can not make assumptions about o[k]. we could add a special handling to allow it to be assignable to that type.

@tomblind
Copy link

tomblind commented Feb 2, 2018

Before 2.7 that assignment worked, although maybe it shouldn't have. I have found a workaround using mapped types, however:

type unknown = {} | null | undefined;

function fn<K extends string, T extends {[I in K]: unknown}>(o: T, k: K) {
    var v: unknown = o[k]; //Works!
}

@mhegazy
Copy link
Contributor

mhegazy commented Feb 2, 2018

Before 2.7 that assignment worked, although maybe it shouldn't have. I have found a workaround using mapped types

Please see my response in #21369 (comment)

@tomblind
Copy link

tomblind commented Feb 2, 2018

Got it - thanks for clearing that up! Not sure if special-casing for {} | null | undefined makes sense or not (especially since there are reasonable alternatives).

@mhegazy
Copy link
Contributor

mhegazy commented Feb 6, 2018

We talked about the unknown type one more time today. @RyanCavanaugh is working on a proposal here. it is going to be a new primitive type.

@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.

@ahejlsberg ahejlsberg added Bug A bug in TypeScript Fixed A PR has been merged for this issue and removed Working as Intended The behavior described is the intended behavior; this is not a bug labels Apr 29, 2018
@mhegazy mhegazy added this to the TypeScript 2.9 milestone Apr 30, 2018
@microsoft microsoft locked and limited conversation to collaborators Jul 31, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Bug A bug in TypeScript Fixed A PR has been merged for this issue
Projects
None yet
Development

No branches or pull requests

5 participants