Home > Net >  Typescript: how do I build an interface containing both an object and a string index type?
Typescript: how do I build an interface containing both an object and a string index type?

Time:06-29

I need to describe an interface where:

  1. A property with a 'billingAddress' key has a value of an Object with specific properties, and
  2. Properties with any other key have a value of a string.

I tried this:

interface DoesNotWork {
  [key: string]: string;
  billingAddress?: {
    foo: string;
  }
}

Typescript complains that Property 'billingAddress' of type '{ foo: string; } | undefined' is not assignable to 'string' index type

Fair enough: when DoesNotWork.billingAddress is defined, Typescript won't know whether it should be assigned a string, an object or undefined.

How do I describe the interface in a way that Typescript will understand?

CodePudding user response:

Use discriminated union so you can mix and match.

interface DoesNotWork {
  billingAddress?: {
    foo: string;
  };
}

const foo: DoesNotWork | { [key: string]: string } = {
  billingAddress: { foo: "value" },
  key: "value"
};

CodePudding user response:

With using Index Signatures because the exact propertyName is not known at compile-time, but the general structure of the data is known, creating a separate interface, to accommodate this data, and afterward composing the Interfaces to achieve the desired object structure, should help solve your problem OR extend using union types to increase the flexibility of values which are expected

This is because in trying to define different fields in the same interface, then you must cater for the option, of different (values) for the other fields aside from the Index Signature field

demo code

//composition approach(1)
interface BillingAddress{
  foo: string;
}

interface DoesNotWork{
  [key: string]: string;
}

interface ComposedInterface{
  indexSignature: DoesNotWork,
  billingAddress? : BillingAddress,
}


//extending value fields using unions approach(2)
interface BillingAddress{
  foo: string;
}

interface DoesNotWork{
   [key: string]: string | BillingAddress;
   billingAddress: BillingAddress;
}
  • Related