Home > Software engineering >  Inferring a partial type of a constant object
Inferring a partial type of a constant object

Time:12-15

Let's say I've got a function that expects a certain interface

interface Foo {
  foo: number;
  bar: number;
  baz?: number;
  buz?: number;
}

const doFoo = (params: Foo) => { /* ... */ };

I also have some constant that contains default values for a subset of Foo:

const BASE_PROPERTIES = {
  foo: 42,
  baz: 9001,
};

doFoo({
  ...BASE_PROPERTIES,
  bar: -1000
});

This works fine. But I'm wondering if there's a way that I can signify that BASE_PROPERTIES contains some parts of Foo. Both to provide intellisense when editing, and make it clear what the constant is used for. Essentially an automated Pick<>.

I could do

const BASE_PROPERTIES: Partial<Foo> = { /* ... */ }

However that will mean that using it in the spread gives an error for foo because Type 'number | undefined' is not assignable to type 'number'. I could as any or as Foo it, but that trades convenience for risk in the event that I actually forgot to include foo.

Likewise, I could use pick

const BASE_PROPERTIES: Pick<Foo, 'foo' | 'baz'> = { /* ... */ }

But that requires me to keep it updated as I go (a bit cumbersome, not particularly DRY for very large objects), and won't give me intellisense as I'm adding further properties, kind of defeating half the point of adding it in the first place.

Is there a way to hint to typescript, that an object should follow the schema of an interface, but that it should figure out how the const actually fits the interface?

CodePudding user response:

You are looking for the satisfies operator introduced in Typescript 4.9

const BASE_PROPERTIES = {
  foo: 42,
  baz: 9001,
} satisfies Partial<Foo>

This will make sure that BASE_PROPERTIES satisfies the type Partial<Foo> while still inferring the literal type.


Playground

CodePudding user response:

I guess you can have a small utility function to do so. Something like

function createBaseProps<K extends keyof Foo>(props: Pick<Foo, K>) {
  return props
}

you should get intellisense and type checks

const BASE_PROPERTIES = createBaseProps({
  foo: 123,
})

and be able to merge the result with your doFoo example

  • Related