Ayfri
Ayfri

Reputation: 637

Typescript interface set type of property from another property from the same interface

I have an interface containing two properties, and I want that the second property type to be equal to the first property, the first property type being a string for example.

interface Argument {
  type: any;
  allowedValues: [insert way to infer type from `type` property]
}

const a: Argument = {
  type: 'string',
  allowedValues: 'test', // only because `type` property is a string
}

type property can be anything but allowedValues should be the same type as type (or an array of it)

Upvotes: 1

Views: 684

Answers (1)

jcalz
jcalz

Reputation: 330086

There is no specific concrete type in TypeScript corresponding exactly to what you consider a valid argument, where the allowedValues property must have the same type as the type property. If you want to be able to represent this at all in TypeScript, you'll probably need to think of it as more of a generic constraint, and use a helper function instead of a type annotation to validate that any given candidate value conforms to the constraint:

    interface Argument<T> {
      type: T;
      allowedValues: T
    }
    const asArgument = <T,>(a: Argument<T>) => a;

Here we are making a generic type Argument<T> that keeps track of the type of the type and allowedValues properties being correlated. You can test it out:

const a = asArgument({
  type: 'string',
  allowedValues: 'test', // okay
});

asArgument({
  type: 123,
  allowedValues: 456
}); // okay

asArgument({
  type: 'string',
  allowedValues: 456 // error! Type 'number' is not assignable to type 'string'
})

If you try to give allowedValues a value of a different type from that of type, you get an error.


Note that by making your Argument type generic, you'll need to drag around the extra generic type parameter T wherever you need to keep track of this constraint. I magine changing all mentions of Argument to Argument<T> and adding T to whatever scope is necessary. So I'd suggest only using this constraint for initial validation of developer-submitted arguments, and then widen it to a concrete type like Argument<any> for use in internal code that assumes it's already been validated.

Playground link to code

Upvotes: 1

Related Questions