Repository: TypeScript
Issue: Relating keys and field constraints of a generic super type constructed with mapped type filtering out properties
Labels: Suggestion,Needs Proposal

# Bug Report

### 🔎 Search Terms

- indexing related keys of mapped types
- supertype mapped type
- excluding keys mapped type

### 🕗 Version & Regression Information

- This is the behavior in every version I tried (4.4, 4.5, 4.6-dev), and I reviewed the FAQ for entries about mapped types

### ⏯ Playground Link

[Playground link with relevant code](https://www.typescriptlang.org/play?ts=4.6.0-dev.20220114#code/PTAEGUFcAcFMCcAqBPOAeRAaUBhAfKAMYD2AdgM4Au8khl5oAhqOTAqJarKMQGaiJQAI2SheASwA2lBONIBzHpEqho8YnHiVxsBnwEcAFoxUATYqFLEVsAB4zSp3AChnIUAHlo2sqACMoAAUlIbcALbEVETE8PCwdNhxEQBuuqAA1rDI5ACUzpxwEGxIXBjY+KAAvKAA3qAA2gDSoHIZWfqCjAyBiE0AuqB2DqYMOKAA-KDNAFyWsKnwOX2zvY0DAL6u7l4+pKAATEFWKiSx8ZSJurD0YjqSIxwWpPMIee4F3FCaKOhYuATVOpNFp7TLIDrLAT9Qb2WCOUYTKFrUCzZ4LUCbNxgHbiXwAZiCON8AUYjgO0TCQjkplgpjeYA+RW+pT+FUBDWarTBHSY3VWAyGcIeY0mMzmCyWK2hgvhuER-JR4vYmO23lxewALEEAJIsRgAdyM4gYkHItJBRm4+qkdKxHC4TIQP1gZX+VVAAAVxIR0q6gZzQe1+IhIQqZcLEWK0cr6tzg308K5GQA5SBhcgYAGOkq-bCkNNCBCJu12RhhaCSXT5B0AQXddUYsz8AAZsEJZtRINxNoycHXqqn02gawRQKBVbt-Ng8dgNbMG03mxjnGPV2v1xuJ+qDvOmIu26iXvBl72a81qnHcHWt8Tp7PZgByRgPlcbt+b7Fq3z7R-P0AAH1AB8hBfZxeEgUg6G3XhXQAVRhYYGEvQcM0QPA8GCFZsDCWZYJyWpXzHdxEEMY0WEMYhIHuYRuDiUxaHNSgLD+QtCEYU1uEEcMGC+J0WWwAAqRM10ZcAKKo0wACFYEEapBAAMlAFDM1cNdiNIhhyHE6jC1AOiGKcJjQFg7ByDkQhuHEFQyLBcgeW44zCPtQoxMo+5pPg6p4MUy9EFU1d3FIAI7DgOhGIsXShEoxxwssAsEDbeJ2LNUAwhaJCgyUtNUOE1cSAoFQgvdSh6jCAYbz2PxsB-KFYL6Jz33fCrQDxWZSWQbAEHUY9nSA2CHyIUljho0AOMMixqTsZzuAfRAHwAOmCch9gAVjxAA2PI1yC+amIAMXEWxaUCfCAs-ScqoOe9hGimlxtG0h0isfVSAaxqP08L89laphSFED5-KIsByDLWA82C2xQpke7Itu2L80pBLhGUUBrRCJhQFI0hKCc-KolIQ5qhKsreWzZ1XQRwt4Dweo6vHc7t0umriHSN73vZjmmoZ-EVgdB9+sG0hht0sbHhBGlbGmoC5sW1aNq21cCd24gDqO0wTrU7nKuuqKILusWIKe4gXrZznmpq3WYvuyn2ECVhCAs8hyAAQgVzn12an7Lf1oybePQJWOS7h9EZLozS0dU8k2IA)

### 💻 Code

```ts
// SuperType<T, C> constructs a super type of T by filtering out properties of T that do not extend C

// Option 1 (the most correct, removes keys)
type SuperType<T, C> = { [K in keyof T as (T[K] extends C ? K : never)]: T[K] }

// Option 2 (not correct, resets fields to never)
// type SuperType<T, C> = { [K in keyof T]: T[K] extends C ? T[K] : never }

// Option 3 (Option 1 and 2 combinded)
// type SuperType<T, C> = { [K in keyof T as (T[K] extends C ? K : never)]: T[K] extends C ? T[K] : never }

// Option 4 (I saw this used in the wild)
// type SuperType<T, C> = Pick<T, { [K in keyof T]: T[K] extends C ? K : never }[keyof T]>

type Nums<T> = SuperType<T, number>

// examples
type A = { a: 10, b: true }
type CA = Nums<A>   // Option 1, 3, 4: { a: 10 }
                    // Option 2: { a: 10, b: never }
type CAK = keyof CA // Option 1, 3, 4: 'a'
                    // Option 2: 'a' | 'b'

function f<T, U extends keyof Nums<T>>(t: T, m: U) {
    // This should be reduced to T, because T extends SuperType<T, *>
    type ShouldBeT = T & Nums<T>

    // This should be reduced to U, since it is keysof T extends U
    type ShouldBeU = U & keyof T

    // n1 expected to be bounded to number, because m is keyof Nums<T>
    const n1 = t[m] // Option 1, 2: T[U]
                    // Option 3: any, error Type 'U' cannot be used to index type 'T'.(ts2536)
    n1.toFixed()    // Option 1, 2, 4: bounded to unknown
                    // Option 3: any type

    // same, n1 expected to be bounded to number, but with a hint
    const n2 = t[m] as SuperType<T, number>[U] // Option 1, 2: ok
                                               // Option 3: Type 'U' cannot be used to index type 'T'.(2536)
    n2.toFixed()    // Option 1, 4: bounded to unknown
                    // Option 2: bounded to number (success!)
                    // Option 3: bounded to number (because of type assertion)
}
```

### 🙁 Actual behavior

- TS cannot relate a key that is a key of a supertype (with same or lesser keys) constructed by mapped type removing some keys
- TS cannot index a generic type with a key of its generic supertype

### 🙂 Expected behavior

- TS can relate a key that is a key of a supertype (with same or lesser keys) constructed by mapped type removing some keys
- TS can index a generic type with a key of its generic supertype

### Reasoning

- any field with key `U` of `SuperType<T, C>` is also a key of `T` and its type extends `C`
- therefore `T[U]` should be allowed because `U` is `keyof T`
- therefore `T[U]` should be `C` because `T[K]` extends `C` for any key in `U`

That is a very common task that you need to filter out some properties from a type. I saw people call it a subtype when in fact it is a supertype. But weirdly enough indexing be keys of the mapped type is not allowed. I saw it as a regression in a big codebase when upgraded to 4.5, but turned out the values were considered `any`. So now they're bounded to `unknown` which is better but still cannot do much further.