typescript - a tighter type cannot feed into a looser type?

Viewed 29
const func: (prm: Record<string, string | number>) => void = (prm) => {
    return;
};

interface Obj {
    key1: string;
}

func({ key1: 'value1' } as Obj); // Argument of type 'Obj' is not assignable to parameter of type 'Record<string, string | number>'. Index signature for type 'string' is missing in type 'Obj'.ts(2345)

How come the Obj object cannot feed into the fuction func while Obj can fulfill the prm required data shape?

1 Answers

The application fails because an object of type Record<string, string | number> should have a string | number value for any string key, which is not the case for Obj.

Consider for example this type-correct func definition:

const func: (prm: Record<string, string | number>) => void = (prm) => {
  const v = prm.someProp
  console.log(v.toLocaleString())
};

Given the type of prm, a property prm.someProp should exist (and it should have a toLocaleString method as string and number do). However, if you call func it with an Obj argument, it will fail at runtime:

func({ key1: 'value1' } as any); // Runtime error

You can get the desired type by making func generic:

const func: <K extends string>(prm: Record<K, string | number>) => void = (prm) => {
  return
};

interface Obj {
  key1: string;
}

func({ key1: 'value1' } as Obj); // No type error

TypeScript playground

Related