typescripttype-inferenceinference

Index Types not Inferring in Typescript


I have a small code where TS drives me crazy...

type MyCustomType<T extends Record<string, string>> = {
  key: keyof T;
};

export const myFunction = <T extends Record<string, string>>(variable: MyCustomType<T>) => {
  const newVar: string = variable.key;
};

Typescript keeps complaining that variable.key can be string | number | symbol and can't be assign to newVar. But I typed my generic object as Record<string, string>.

So, why TS can't guess it's a string ?

How can I type these, without using as

Thanks a lot !


Solution

  • The compiler does not infer keyof T to be string because it does not have to be a string. Your constraint merely states that every string key must have a string value. But T might also have number or symbol keys.

    myFunction<Record<0, string>>({ key: 0 })
    // no error, the constraint is fulfilled
    

    So we should explicitly forbid number and symbol keys.

    type MyCustomType<
      T extends Record<string, string> 
        & Record<number | symbol, never>
    > = {
      key: keyof T & string;
    };
    
    export const myFunction = <
      T extends Record<string, string> 
        & Record<number | symbol, never>
    >(variable: MyCustomType<T>) => {
      const newVar: string = variable.key;
      console.log(newVar)
    };
    

    This still does not silence the error. TypeScript is not able to deduct that keyof T is a string. After all, it could still have number properties of type never (which practically is not possible but you could still explicitly pass a type containing never values). But we can now "safely" intersect keyof T with string.

    Playground