Home > OS >  Utility type (Extract) in conjunction with generic (keyof T) gives type that nothing can be assigned
Utility type (Extract) in conjunction with generic (keyof T) gives type that nothing can be assigned

Time:07-16

Trying to answer this question has left me with more questions than answers. I'll let the code speak for itself:

type MyAnimals = { name: "dog", fleas: 2 } | { name: "cat" }
function GetKeys<T extends MyAnimals>(animal: T) {
  for (let k in animal) {
    let sansAssertion = k;
    sansAssertion = 'name'; // err -> whyyyyy?
    sansAssertion = 'fleas'; // err -> I get it...
    sansAssertion = 'hohoho'; // err -> yeah, that's Bullsh1t

    const thisIsConst = 'name' as const; // the type is 'name', not string, FOR SURE
    sansAssertion = thisIsConst; // err -> dafuck? Still not?

    let withAssertion = k as keyof T;
    withAssertion = 'name'; // works -> aha!
    withAssertion = 'fleas'; // err -> yeah
    withAssertion = 'hohoho'; // err -> Bullsh1t

    let letsBeExplicit: Extract<keyof T, string> = 'name'; // err -> okay, expected, by now. 
    // Can I assign ANYTHING to this??

    type SpelledOut = Extract<('name' | 'fleas') | 'name', string>
    let noGeneric: SpelledOut = 'name'; // works -> yup, okay, it's not _just_ the Extract that's broken

    type LessSpelledOut = Extract<keyof ({ name: string, fleas: number} | { name: string }), string>;
    let fromKeys: LessSpelledOut = 'name'; // works -> yeees
    fromKeys = 'fleas' // err -> yeees
  }
}

Playground

In case my question isn't clear by now: TypeScript is clearly able to understand the keyof T type and acts as expected. keyof T contains a union of a bunch of different strings (only one, in this case). It would be expected, that Extract<ABunchOfStrings, string> === ABunchOfStrings, yet it is not if ABunchOfStrings comes from a generic type keyof T. Whyyyyy?

  • Related