1

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?

2 Answers 2

1

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"
};
Sign up to request clarification or add additional context in comments.

1 Comment

Seems to work great! I threw in a type definition as well: type Customer = DoesNotWork | { [key: string]: string }; const foo: Customer = ...
0

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;
}

1 Comment

For (1): it looks like you define a property called indexSignature, whose value is intended to be an object containing a property whose key is any string, and whose value is a string. But we want the mapped type a level up, where you put the indexSignature property. (2) comes closer: billingAddress's type is restricted to an object with specific properties. But with [key: string]: string | BillingAddress, we can now define anything to be a BillingAddress. We want only the billingAddress key to use the value BillingAddress. Anything else should be a string.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.