Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TS branded string as key of the object

Imagine, that I have class Foo with string identifier.

class Foo {
    id = '123' as FooId;
}

I try to ensure static typing of it using a brand enum.

enum FooIdBranding {}
type FooId = string & FooIdBranding;

So now, my goal is specific object, where the key is FooId and the value is Foo.

type fooCache = { [key: FooId]: Foo };

Unfortunately, it doesn't work:

TS1023: An index signature parameter type must be 'string' or 'number'

I thought, that the Record is my solution, but is doesn't work too.

type FooCache = Record<FooId, Foo>;

({} as FooCache)['123' as FooId] = new Foo();

TS 7017: Element implicitly has an 'any' type because type Record<FooId, Foo> has no index signature

Is there a correct way in TypeScript to resolve this problem?

like image 662
Shock Avatar asked May 07 '19 10:05

Shock


1 Answers

"Symbol and Template String Pattern Index Signatures" were added to TypeScript 4.4, so this is now possible.

type FooId = string & {brand: 'FooId'};
const id1 = '1' as FooId
const id2 = '2' as FooId

class Foo {
  constructor(public id: FooId) {}
}

type fooCache = { [key: FooId]: Foo };

const foo: fooCache = {
  // Type '{ key: Foo; }' is not assignable to type 'fooCache'.
  // Object literal may only specify known properties, and 'key' does not exist in type 'fooCache'.(2322)
  // (property) key: Foo
  key: new Foo(id1)
}

// All good
const bar: fooCache = {
  [id1]: new Foo(id1)
}

Example in the TS playground.

like image 79
Klaster_1 Avatar answered Oct 11 '22 12:10

Klaster_1