Home > Enterprise >  Is there a way to elegantly type fields of an object literal without typing the object literal itsel
Is there a way to elegantly type fields of an object literal without typing the object literal itsel

Time:12-01

Let's assume I have these 2 types:

type Foo = {
  foo: string
}

type Bar = {
  bar: number
}

Is there a way to type individual fields of an object literal (I'm looking for the right syntax if it exists), without creating a wrapper type?

This is what I want to avoid:

type Wrapper = {
  a: Foo
  b: Bar
}

const x: Wrapper = {
  a: { foo: 'foo' },
  b: { bar: 123 }
}

This is what I'm trying to do:

const x = {
  // x.a should be of type Foo, enforced by the compiler
  a: { foo: 'foo' },
  // x.b should be of type Bar, enforced by the compiler
  b: { bar: 123 }
}

What I considered, but is not suitable:

  1. Using a Record type makes no sense, as I lose the individual fields and their individual types:
const x: Record<string, Foo | Bar> = {
  a: { foo: 'foo' },
  b: { bar: 123 }
}
  1. Type casting (or whatever its called in TS) is also not suitable, as now I loose compiler checks and content assist. At least with this version the type of x is correct:
const x = {
  a: { foo: 'foo' } as Foo,
  b: { bar: 123 } as Bar
}

CodePudding user response:

It seems like you are looking for the satisfies operator which will be rolled out in TypeScript 4.9. It allows to preserve the literal type while still type checking with some constraint.

const x = {
  a: { foo: "223" },
  b: { bar: 123 }
} satisfies Record<string, Foo | Bar>

x.a.foo // string
x.b.bar // number

Playground

  • Related