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

Index access type from intersection #17929

Closed
olegdunkan opened this issue Aug 19, 2017 · 6 comments
Closed

Index access type from intersection #17929

olegdunkan opened this issue Aug 19, 2017 · 6 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@olegdunkan
Copy link

olegdunkan commented Aug 19, 2017

TypeScript Version: playground

Code

var a: "x" | ("y" & "z");
var b: {x:number, y:string, z:boolean};
var c: keyof typeof b;

c = a; //ok 

var x:typeof b[typeof a];

Expected behavior:

An indexed access type T[K] requires K to be a type that is assignable to keyof T
...
T[K] is resolved as follows:

If K is a union type K1 | K2 | ... | Kn, T[K] is equivalent to T[K1] | T[K2] | ... | T[Kn]

#11929

I expected the type of x to be number, because "x" | ("y" & "z") is assignable to keyof {x:number, y:string, z:boolean}

T["x" | ("y" & "z")] = T["x"] | T["y" & "z"] = number | ? (never or empty) but result of union is the number type;
Edited:
In other words I expected T["y" & "z"] to be never
Actual behavior:
error - Type '"y" & "z"' cannot be used as an index type

@mhegazy
Copy link
Contributor

mhegazy commented Aug 22, 2017

The compiler verifies that an index operation is legal. the way it does that is either the key is part of the known keys of the indexed type or constraint to it. in this case "y" & " z" are just like "foo", and not part of the known keys for the type b, which is "x" | "y" | "z".

@mhegazy mhegazy added the Working as Intended The behavior described is the intended behavior; this is not a bug label Aug 22, 2017
@olegdunkan
Copy link
Author

olegdunkan commented Aug 22, 2017

@mhegazy, thanks I know that complier works as intended, if we are looking at the sources. In my case we have union of types as index type, complier sees that first constituent x is legal key name, second "y"&"z" is not, why can't compiler substitute T["y"&"z"] with never instead tsc throws error?

@mhegazy
Copy link
Contributor

mhegazy commented Aug 22, 2017

at run-time an index with an unknown property would result in undefined. if the compiler did not limit the access on only known index types, every generic T[K] would be potentially undefined and you would have to check for that on every use.

@olegdunkan
Copy link
Author

@mhegazy now I see, thanks a lot for the answer.
But what will be if we reduce union to not never ? We will get property with not undefined type.
For example, T["x"] | T["y" & "z"] = number | never = number //ok, property with type number
T["x" & "z"] | T["y"&"z"] = never | never = never //bad, undefined property at runtime
T["foo"] = never //bad, throws error

@mhegazy
Copy link
Contributor

mhegazy commented Aug 23, 2017

T["y" & "z"] should not be never, it should be undefined. and that does not reduce.

@olegdunkan
Copy link
Author

@mhegazy yes, I know, it was my suggestion

why can't compiler substitute T["y"&"z"] with never

the reason of my issue I want to simplify this:

type A<T, K extends ("x"|"y") & keyof T> = T[K];
var a:A<{x:number, y:string, z:boolean}, "x"|"y">; //ok, type of a is number | string

to this:

type A<T> = T[("x"|"y") & keyof T];
var a:A<{x:number, y:string, z:boolean}>; //bad, type of a is any 

Because every time I instantiate A<T> I have to remember properties that are constrained in A.

Maybe there is some workaround to get it.

@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

2 participants