4
votes

I have a function like this:

interface IUseTest {
  settings: {
    id: string
  }
};

const useTest = (properties: IUseTest) => {
  const { settings } = properties;
  
  const test = (
    item: {
     [settings.id]: string | number, // Error here
     [key: string]: any
    }
  ): object => {
    // function logic, doesn't matter
  };
  
  return {
    test
  };
};

I should set an item with required key which I get from the settings object, but I got the error:

A computed property name in a type literal must refer to an expression whose type is a literal type or a 'unique symbol' type.

what I have to do?

UPDATE: is there a way to not use an interface?

UPDATE: the item can be like this: { id: 'someId' } or { key: 'someKey' }

UPDATE: typescript's version is 4.0.3

3
Hi, could you show how you would use the function, i.e.: how the parameter item should look?yi fan song
@yifansong, hi, the item should looks like: { id: 'some-id' ...other } or { key: 'some-key' ...other }, that's means that object can have key id or key (id === key)meine
So the item parameter actually looks like this: { string: any, ...rest } that first property name being properties.settings.id?yi fan song
@yifansong, yep, that's rightmeine
does const assertion work?yi fan song

3 Answers

1
votes

You can use Generics and Mapped Types, like so:

interface IUseTest<T extends string> {
  settings: {
    id: T
  }
};

const useTest = <T extends string>(properties: IUseTest<T>) => {
  const { settings } = properties;
  
  const test = (
    item: { [settingsId in T]: string | number } & {
     [key: string]: any
    }
  ): object => {
    // function logic, doesn't matter
  };
  
  return {
    test
  };
};

Here, <T> is the generic and { [settingsId in T]: string | number } is the Mapped Type.

0
votes

Is this what you want?

const settings = {
  id: 'id',
};
type Settings = typeof settings;
interface Item extends Settings {
  [key: string]: any;
}
const test: (item: Item) => object = (item) => {
  return {};
  // function logic, doesn't matter
};
0
votes

You could try const assertion.

const settings = {
  id: 'id'
} as const;

That should fix your error. If you're running a typescript version lower than 3.4 then typecast your id property in settings.

const settings = {
  id: 'id' as 'id'
};