Home > Enterprise >  How to infer property values from arrays of objects in Typescript?
How to infer property values from arrays of objects in Typescript?

Time:12-03

I'd like the TypeScript compiler to infer the names of properties on an object so that it's easier to invoke the appropriate functions later. However, despite considering invoking functions, TypeScript doesn't give any intellisense of the functions I can invoke.

Taking into account the following example:

interface InputBase {
  alias: string;
}

const input: Array<InputBase> = [
  { alias: 'getNotes' },
  { alias: 'getComments' },
];

const client = input.reduce((acc, curr: InputBase) => {
  return {
    ...acc,
    [curr.alias]: () => {
      return curr.alias   ' call';
    },
  };
}, {});

client.getNotes();

My problem is really the lack of inference in the client variable, because currently the data type is {} despite appearing in the terminal {getNotes: ƒ, getComments: ƒ}.

How can I resolve this?

CodePudding user response:

One way to resolve this is to use a type assertion to tell the TypeScript compiler that the type of the client variable is actually an object with the same properties as the InputBase interface.

You can do this by either using the as keyword, or the <> syntax.

For example, you can use the as keyword like this:

const client = input.reduce((acc, curr: InputBase) => {
  return {
    ...acc,
    [curr.alias]: () => {
      return curr.alias   ' call';
    },
  } as { [key in InputBase['alias']]: () => string };
}, {});

Now, when you type client., you'll be presented with autocompletion options that match the values of the InputBase.alias property.

CodePudding user response:

In TypeScript, the type of the client variable in your example would be inferred as {}, because you are creating an object with dynamic property names using the reduce method.

In order to provide type information for the client variable, you can use the Record type from TypeScript. This type allows you to define an object type with a set of known keys, and the values can have a specific type.

Here is an example of how you could use the Record type to provide type information for the client variable:

interface InputBase {
  alias: string;
}

const input: Array<InputBase> = [
  { alias: 'getNotes' },
  { alias: 'getComments' },
];

// Define the type of the client variable as a Record with string keys and
// values that are functions that return a string.
const client: Record<string, () => string> = input.reduce((acc, curr: InputBase) => {
  return {
    ...acc,
    [curr.alias]: () => {
      return curr.alias   ' call';
    },
  };
}, {});

// Now TypeScript will provide intellisense for the client variable,
// and you can see the list of available methods when you type `client.`
client.getNotes();

Alternatively, you can use a type assertion to explicitly specify the type of the client variable. This allows you to provide a type for the client variable without using the Record type. Here is an example:

interface InputBase {
  alias: string;
}

const input: Array<InputBase> = [
  { alias: 'getNotes' },
  { alias: 'getComments' },
];

// Use a type assertion to explicitly specify the type of the client variable
const client = input.reduce((acc, curr: InputBase) => {
  return {
    ...acc,
    [curr.alias]: () => {
      return curr.alias   ' call';
    },
  };
}, {}) as { [key: string]: () => string };

// Now TypeScript will provide intellisense for the client variable,
// and you can see the list of available methods when you type `client.`
client.getNotes();

I hope this helps! Let me know if you have any other questions.

  • Related