Repository: TypeScript
Issue: values of mapped types contain impossible union members in some circumstances and not others
Labels: Needs Investigation

# Bug Report

<!--
  Please fill in each section completely. Thank you!
-->

### 🔎 Search Terms

<!--
  What search terms did you use when trying to find an existing bug report?
  List them here so people in the future can find this one more easily.
-->

 - mapped types
 - correlated types

### 🕗 Version & Regression Information

<!-- When did you start seeing this bug occur?

"Bugs" that have existed in TS for a long time are very likely to be FAQs; refer to
  https://github.com/Microsoft/TypeScript/wiki/FAQ#common-bugs-that-arent-bugs

If possible, please try testing the nightly version of TS to see if it's already been fixed.
For npm: `typescript@next`
This is also the 'Nightly' version in the playground: http://www.typescriptlang.org/play/?ts=Nightly

Note: The TypeScript Playground can be used to try older versions of TypeScript.

Please keep and fill in the line that best applies:
-->
- This behavior worked as expected (although there were other problems with this example) in 4.5.5 and is broken in 4.6.2


## Repro code

```ts
type Article = { type: "article", headline: string };
type User = { type: "user", name: string };
type Photo = { type: "photo", x: number, y: number };
type ArgUnion = Article | User | Photo;

// imagine this dispatch table were imported from somewhere else, perhaps like `import * as dispatchTable from "./methodsDir";`
let dispatchTable = {
    article(value: Article) { },
    user(value: User) { }
};

// DispatchableTypes = "article" | "user", as expected...
type DispatchableTypes = Extract<ArgUnion["type"], keyof typeof dispatchTable>;

/**
 * ArgMap = { article: Article, user: User }
 * again, as expected
 */
type ArgMap = { [key in DispatchableTypes]: Extract<ArgUnion, { ["type"]: key }> };

type Methods = { [K in keyof ArgMap]: (value: ArgMap[K]) => void }

const methods: Methods = dispatchTable;

/**
 * Now we can use our dispatch table as a kind of multimethod for members of our union type!
 * 
 * Why is this type necessary though? It doesn't seem to be doing anything in particular
 */
type MethodAndArg<K extends keyof ArgMap = keyof ArgMap> =
    { [P in K]: { method: P, arg: ArgMap[P] } }[K]

function callMethodWithArg<K extends keyof Methods>(methodAndArg: MethodAndArg<K>) {
    // The combination of mapped types allows the compiler to know that methodAndArg.method and methodAndArg.arg have correlated types
    methods[methodAndArg.method](methodAndArg.arg);
}

/**
 * For some reason this doesn't work?
 */
function callMethodWithUnion<K extends keyof ArgMap>(data: ArgMap[K]) {
    /** 
     * `data.type` is given the type `(K & "article") | (K & "user") | (K & "photo")` here
     * This is puzzling because "photo" is absolutely not a possible member of ArgMap[keyof ArgMap]["type"]
     * and no other part of the code infers "photo" for this type?
     */
    return methods[data.type](data); //error! Argument of type 'ArgMap[K]' is not assignable to parameter of type 'ArgMap[K & "photo"]'.
}

/**
 * it's not just some quirk of the extra layer of mapped types either, the specific structure of `MethodAndArg` is important
 * all of these types have the same problem as just using ArgMap directly
 */
type MappedArgMap<K extends keyof ArgMap = keyof ArgMap> = { [P in K]: ArgMap[P]}[K];

type MappedArgMap2<K extends keyof ArgMap = keyof ArgMap> = { [P in K]: { arg: ArgMap[P] }}[K];

type MappedArgMap3<K extends keyof ArgMap = keyof ArgMap> = { [P in K]: ({ type: P } & ArgMap[P]) }[K];

function callMethodWithArg2<K extends keyof Methods>(arg: MappedArgMap<K>) {
    methods[arg.type](arg); // arg.type is (K & "article") | (K & "user") | (K & "photo")
}

function callMethodWithArg3<K extends keyof Methods>(arg: MappedArgMap2<K>) {
    methods[arg.arg.type](arg.arg); // arg.arg.type is (K & "article") | (K & "user") | (K & "photo")
}

function callMethodWithArg4<K extends keyof Methods>(arg: MappedArgMap3<K>) {
    methods[arg.type](arg); // arg.type is (K & "article") | (K & "user") | (K & "photo")
}
```



<details><summary><b>Output</b></summary>

```ts
"use strict";
// imagine this dispatch table were imported from somewhere else, perhaps like `import * as dispatchTable from "./methodsDir";`
let dispatchTable = {
    article(value) { },
    user(value) { }
};
const methods = dispatchTable;
function callMethodWithArg(methodAndArg) {
    // The combination of mapped types allows the compiler to know that methodAndArg.method and methodAndArg.arg have correlated types
    methods[methodAndArg.method](methodAndArg.arg);
}
/**
 * For some reason this doesn't work?
 */
function callMethodWithUnion(data) {
    /**
     * `data.type` is given the type `(K & "article") | (K & "user") | (K & "photo")` here
     * This is puzzling because "photo" is absolutely not a possible member of ArgMap[keyof ArgMap]["type"]
     * and no other part of the code infers "photo" for this type?
     */
    return methods[data.type](data); //error! Argument of type 'ArgMap[K]' is not assignable to parameter of type 'ArgMap[K & "photo"]'.
}
function callMethodWithArg2(arg) {
    methods[arg.type](arg);
}
function callMethodWithArg3(arg) {
    methods[arg.arg.type](arg.arg);
}
function callMethodWithArg4(arg) {
    methods[arg.type](arg);
}

```


</details>


<details><summary><b>Compiler Options</b></summary>

```json
{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictPropertyInitialization": true,
    "strictBindCallApply": true,
    "noImplicitThis": true,
    "noImplicitReturns": true,
    "alwaysStrict": true,
    "esModuleInterop": true,
    "declaration": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "target": "ES2017",
    "module": "ESNext",
    "moduleResolution": "node"
  }
}
```


</details>

**Playground Link:** [Provided](https://www.typescriptlang.org/play?jsx=0&ts=4.6.2#code/C4TwDgpgBAggTsAlgYwDbQLxQN5VJALigCIBDBFdYgGigAsJSATVRAOwiIGdg52BzKAF8A3AFgAUPmgBVLhDhQsuaUWIBXeXBpQ2pALacoPPm0GjJ0qAAU6Ae2B2lOPOCPEw9xzoAeRNur6AEYKtCD+gSGKFlJusHD8MmyIdmzO8Eho0AA+UHIKULm2DnbiEpLowFBMiFxgpMDIdAAqpEHoztiSUD1Q5JnoABQAbqSo6kYZlBAAlC5C1N29mgojYxNE+XBzuEKSMZIA9IdQACK19Y10bejNblzOZBRZxIUkK9q0pA8QPpDIwAgTAAdKDLHFznUGk0bhA7pAHlgAKI+XikAEAHngiWSqQA2sRpMQALq0ADWEBAdgAZq5IDTqhdoS1YQA+MpHABUnO6nPi-AAsqQwJ0+s90EQpllaB9NlphLy+vxSOwvj8-hAAUDeYdwZB+UKRcooHiKSAoOwzkyrrD4RAuMSiCi0ZjsUkUmxaLgCUTHVAzcJWcIObF9QKIMB7ExES48QBpC1pM0M7GGv1rcaTBKG+PEuYYIPDOyIJgK8oSZCpHhQQyRuzRojhuvR5w1KFXVrtCAhw7cxUAOTsAHcoEPoMhSGkVlA7OpFG3Lk08LC+g9SP72KWGfp1KgkLWo1BqXZFIZggoHgzZ4p1Li0tIAISKxUAdTo5tqeDon6sHGQ9q4chzTrdR+DoAB+KAAEkqiYOx7TYAByKp5AgfQ8CcEJqmLMw+jYEBIwERMoHqZ5d3IHU9WgJsoxgNgmGxDEE1+QF6IeZNaVTYVnA4g1hSDDAlh6b1rGIuM-VwA96yIawvgSSVs2FPFrGJYRhFzSRJGpW8AQ9KAJ1QVAaPrF9EEjRjmNRCA2P9SkGWM6NWUGKSGPo7FGwjWi3ISJjWR2ISoGOKBmgYfS7GCdgGj07dhUgUtpDXQzhweSNx3CsBEHQRRHH9Nhhy-Boa08+s6IYhJgRcvDSxc0rsWBchBGuYY0rgOAIFQBogTpe0Apcrg8Rq7z+Aq4qmGJZzRtq8qGpmMo9nLXseQkKA+QAMRPYxwugNrvlSL9PzghDkNHE8yXAyiJG0thdL2gyjNG0zI3dVImKgFjrJbXiuLAJymAaUgFMFJTxP85bekWqAApWqAAAM-uAUhgWkGGLQefhEGa+9QqsGHBgTAAyEh+mmYg5lyPGoEJjQtFJt4KapzwSlJlGGDaqG+RCz9PzAdQAC9edYXCQgnacPC8OxXk-NouDscZAVQc08qqdcwDsLguEQLsivPRQU0UsBTTszj9eJH03BJdmqt0JwHFZkj+hnWlUrCphoHYakLxIRnvCPDbCJStxzrB3pOV1YOoDa4A5zSPq8XhxHpHG+PZsCw4FDgE8H35QJrKqBkrEQ77c0Q1HreV9XEH4PQtZy0iDAjAp87iQv9fjSmvfFklEOBfZNIkRbFTMxCHiVqAACtNBQraoAAR3URA4DJR2v2gFi4HXDqQEb2l9FirqEreszWdoZ26k1RBqRQYxeHUAE52gBkYYcqb+BRrn9FVhBJ2AC6rENOLvqvXejZL6+seJGz4j9UUykxJ+iLipIQuYQx-z3mVIGYAABMQCrIgIgd9cBVJjboIErGUSlpxJEFwA1QGOYVLCEQeJZBcR-5Am+gAZmwaxT6eCwFYFAcQ6BZC0gUKgIMFQbgZJqUJvAvM6lGF9yujdNId0HKPToNiLBlkuHsQgQ5LgTlqFQBYWgw0vlQa9CKs2fqDUkZuHGjNOaCidJIFumMe6zY1HYg4Voj6OjCFGNGvowYhjjHfU0X5HAvVAl4hsTYxOwTpoJFmr3csiiXHKLcaoo+2IAAsnDfG2X8Xogx8kjGoPYWYyJ4dY5xLsQk-gySJBCCAA)
      
### 🙁 Actual behavior

ArgMap[keyof ArgMap]["type"] is sometimes inferred to be inhabitable by "photo", which is clearly impossible.

### 🙂 Expected behavior

ArgMap[keyof ArgMap]["type"] should only have types that are actually possible