Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Define typescript object shape without index signature

Tags:

typescript

I'm really curios if that somehow a design gap in TypeScript. Let's say I have a function, that takes any objects that fulfills this interface

interface Params {
    [key: string]: string | number | boolean | undefined | null;
}

So the key must be a string and the type of the properties can be a primitive or void.

If I now specify some method that takes a specific interface which as such fulfills the Params interface I get the error, that the other interface doesn't have an index signature. So the other interface may simply look like.

interface Foo {
    bar: string;
}

I also tried to change the signature to Record<string, string | number | boolean | undefined | null> but that also gives the missing index signature error.

My whole code then may look like this. To give a full picture. So I need to have the key and value type of the object specified to be able to do certain operations in Object.entries

function specificFunction(obj: Foo) {
  genericFunction(obj);
}

function genericFunction(params: Params) {
  Object.entries(params).forEach(([key, value]) => {
    …
  })
}

EDIT: Important note, the behavior of the specificFunction should stay the same, as it should be used to narrow done the allowed interface, because in this special case only objects with certain properties are allowed to ensure a certain result.

like image 927
DaSch Avatar asked Mar 01 '21 07:03

DaSch


People also ask

How do you define object of objects type in TypeScript?

To define an object of objects type in TypeScript, we can use index signatures with the type set to the type for the value object. const data: { [name: string]: DataModel } = { //... }; to create a data variable of type { [name: string]: DataModel } where DataModel is an object type.

Has an any type Because type Typeof globalThis has no index signature?

The error "Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature" occurs when we try to access a property that doesn't exist on the global object. To solve the error, extend the global object and add types for the necessary properties.

What is index signature in TypeScript?

Index signature is used to represent the type of object/dictionary when the values of the object are of consistent types. Syntax: { [key: KeyType] : ValueType } Assume that we have a theme object which allows us to configure the color properties that can be used across the application.

How do you pass an object as a parameter in TypeScript?

Inside the function we assign the parameters to properties in the object. To do this, we have to specify the this keyword, which refers to the calling object. The variables and parameters may have the same names. Anything we pass to the constructor as an argument, will be assigned to the property of the object.


1 Answers

genericFunction expects type with index signature.

Foo does not have index signature by the default because it is an interface.

But there is a small hint. If you use type keyword to declare Foo instead of interface - it will work.

Why?

Because type's have index signature by the default.

See this answer.

So, next code will compile:

interface Params {
    [key: string]: string | number | boolean | undefined | null;
}

// use type here instead of interface
type Foo = {
    bar: string;
}

function specificFunction(obj: Foo) {
  genericFunction(obj);
}

function genericFunction(params: Params) {
  Object.entries(params).forEach(([key, value]) => {

  })
}

Playground

UPDATE 2 If you don't have control over Params and Foo, you can use next utility type:

interface Params {
    [key: string]: string | number | boolean | undefined | null;
}

interface Foo {
    bar: string;
}

type Values<T> = T[keyof T]

type MakeIndexed<T> = {
    [P in keyof T]: T[P]
}

function specificFunction(obj: MakeIndexed<Foo>) {
    genericFunction(obj);
}

function genericFunction(params: Params) {
    Object.entries(params).forEach(([key, value]) => {

    })
}
like image 70
captain-yossarian Avatar answered Oct 21 '22 21:10

captain-yossarian