Repository: TypeScript
Issue: Type inference not working as expected when using key remapping in mapped types
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, key remapping using as, type inference

### 🕗 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:
-->
I tested this with all versions available on typescriptlang.org/play including nightly. I was unable to test this on versions < 4.1 because key-remapping does not exist prior to version 4.1.

### ⏯ Playground Link


<!--
  A link to a TypeScript Playground "Share" link which shows this behavior

  The TypeScript Workbench can be used for more complex setups, try
  https://www.typescriptlang.org/dev/bug-workbench/

  As a last resort, you can link to a repo, but these will be slower for us to investigate.
-->
[Playground link with relevant code](https://www.typescriptlang.org/play?ts=4.2.3#code/PTAEGcEsFsAcBsCmoCyBDAngI2TBjpEA7AFzRMgHsjQAzSgJ1BMXAqIHMAuAKBI1jIAypUIAeACoA+UAF5QAbwD6SgNaQiAEy6gARCMK6ANKCyUAHom2gJAXz4DkAOWrJ5ytRuu6XRRLvt+QVRMHEkZeQNEcNAAH1BfRB5aAFciAGMKalAo8IAKADc0eBTEHQkASh10bGjpRQZEEhSGGg91LR19UX8TM0trIpLEW3tUjKyaRLyqkNqxNNUiSgB3IhkFRubWxRUO70SA+x4HYPQSdIALAGE0cFZJUERzFi1wXc9O0ABpWxNvp4vYiad5sBgaDgmABKEUUAG0AGqgDQ2UB3UAIuG6PZeXQAXTxOkKaHBaFIOgRFTkMihx3GmSoNGg5Cuj2erxBH32Ol+-0BHNBJHBnGhUmJpPJNhM6TurGqLJusvAkn+otmUMUPFA2tA6WobFAShl9zkuqVcKKEpIADocVo8VqdSBDcbcO9noJMlZmJRQI10ohIAVkGS0QwOClCKRQJRaMxHD9kUQ2Ig0JoY3GEY7tVsWjQjbLxZAySQKjxjs6AKLmNBwJCgACMPGdABFEOl4CSIfHBO7zAhIOlICR4BhQCtGKp3rQNIgTCRLiHw5HiCQe8hYzkeqBLmTNEgmJB3hpaIgGI103rz+2Rxhrc2wABJJOvSbFUegFImgDkYIh37RLRQG-RZljWACNBTNMMz0RI4i3QxAPTb8iEjHAGAAkhfUaWgkEyZhFyTU9r3TIJWDoBhRFMRB4FWXg9WTNcVmHS5qwHIcSAkRx3nkZkLkuMQajCVDoHQqQTD-EVPyIJZVnWPIojyABWCoTAUbMElcIkqVkGQGyMDSoiJBR+isWwdJkUz0wAKlAAAmcsywfUBq1rfB7OciRCL1OBIAPIiz3eBdkGeNB8PAWtkDI950TQMxg3o-UmJYrjBEfIhiOIANTT4q4FJ6ZTVM1HVNL8bTqUbAySudLylwjKM1ywhDEAAWl3LR-JlIhljXHAApI3VGH9W8TA051EGDGgF3IF8aPgI9iBNDRh2LeAP1gSjYEoe4gu8oab3XcdLj8qKBAhQyeh0cBt10iAemtKzQEcoA)

### 💻 Code

<!-- Please post the relevant code sample here as well-->
```ts
// simple Maybe implementation for testing:
type Some<T> = {__kind: "Some", boxed: T}
type None = {__kind: "None"}
type Maybe<T> = Some<T> | None
function Some<T>(value: T): Maybe<T> {return {__kind: "Some", boxed: value}}
function None(): Maybe<unknown> {return {__kind: "None"}}


type MatchCases<T extends {__kind: K}, K extends string, R> = {[V in T as V["__kind"]]: (variant: V) => R}

function match<T extends {__kind: K}, K extends string, R>(variant: T, cases: MatchCases<T, K, R>): R {
    const _case = cases[variant.__kind]
    // _case is expected to receive an argument of type K instead of V
    return _case(variant)
}

// Example 1
// Declaring types explicitly works fine, the argument type of Some handler is inferred correctly.
// I intentionally use 'string' and 'unknown' instead of "None | Some" and 'number'
// to reflect the inferred types from below:
const withExplicitTypes = match<Maybe<number>, string, unknown>(Some(5), {
    None: () => 1,
    Some: ({boxed}) => boxed * 2
})

// Example 2
// The compiler infers the exact same types as above:
const withTypeInference = match(Some(5), {
    None: () => 1,
    // But the argument to Some-handler cannot be inferred correctly:
    Some: some => some.boxed 
})
```

### 🙁 Actual behavior

I might be misusing the key remapping feature, but while implementing the above mentioned `match` function, I ran into following behavior:
* calling `match` above with explicit generic types works as expected (Example 1)
* the compiler infers the exact same types when not provided explicitly, but the arguments to the case handlers are inferred as `any` (Example 2), even that intellisense initially proposes the correct type while typing (see [1])
* when trying to call a case function in the body of `match`, the expected type of the argument is `K` instead of `T`.

### 🙂 Expected behavior

<!-- What you expected to happen instead, and why -->
* I'm expecting `_case` to require an argument of type `V` as declared in the mapped type (`(variant: V) => R`).
* Based on the inferred types of `MatchCases`, the argument of the Some-handler should be inferred to type `Some<number>`.

[1]:

![image](https://user-images.githubusercontent.com/7881606/118405286-724dd900-b677-11eb-9892-bf4158e7c93c.png)