Home > Mobile >  How to define object accepted argument type for function in typescript
How to define object accepted argument type for function in typescript

Time:07-20

Lets say I want to define a function that accepts one argument that must be an object which keys are strings and values can be for example number | string like it done in the bottom example.

const fn = (param: Record<string, string | number>) => {
  console.log(param);
};

const p = {
  id: 1,
  name: 'John'
};

fn(p);

the above example will work just fine, but when I want to give an explicit type to variable p with using typescript's type as in the bottom example, everything working just fine again.

const fn = (param: Record<string, string | number>) => {
  console.log(param);
};

type User = {
  id: number;
  name: string;
}

const p: User = {
  id: 1,
  name: 'John'
};

fn(p);

But when defining type with the typescript interface as in the example below I'm getting an error saying
TS2345: Argument of type 'User' is not assignable to parameter of type 'Record<string, string | number>'.
Index signature for type 'string' is missing in type 'User'.

const fn = (param: Record<string, string | number>) => {
  console.log(param);
};

interface User {
  id: number;
  name: string;
}

const p: User = {
  id: 1,
  name: 'John'
};

fn(p);

So what is the reason for such a behavior? How can I define type for function argument to be an object which keys should be string and values can be union type for example string | number and will work with both types and interfaces?

CodePudding user response:

REVISED:

You can destructure the object p as such when calling the function:

fn({ ...p });

This takes all of the properties of p and puts them on a new object.

It is also possible to create a new object for the purposes of passing to the function:

const params = {
    ...p,
};

fn(params);

CodePudding user response:

This should be due to the fact that interfaces are "open" while type aliases are closed, meaning they can not be extended after their initial declaration, unlike interfaces, that can be declared again - which means you could add properties to the interface, that are not assignable to Record<string, string | number>. This also relates to declaration merging

See this playground for more details

  • Related