Shaun Luttin
Shaun Luttin

Reputation: 141522

Type for object that has one and only one property from a list of valid property names

How can we model this without creating a union type that has each possible object?

type ValidRootPropertyNames =
  'Property1' |
  'Property2';

type ObjectWithRootPropertyNameFromList =
  { Property1: string; } |
  { Property2: string; };

const obj1: ObjectWithRootPropertyNameFromList = { // okay
  Property1: 'foo',
};

const obj2: ObjectWithRootPropertyNameFromList = { // okay
  Property2: 'foo',
};

const obj3: ObjectWithRootPropertyNameFromList = { // error
  Property3: 'foo',
};

The above does what we need; the problem is that it becomes cumbersome when there are dozens of valid property names.

Upvotes: 1

Views: 46

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249666

You can use the distributive behavior of conditional types to create the union automatically from the union of keys:

type ValidRootPropertyNames =
'Property1' |
'Property2';

type ObjectWithRootPropertyNameFromList =
    ValidRootPropertyNames extends infer T ? // Introduce a type parameter to have distributive behavior 
    T extends string ? Record<T, string> : never : never;

const obj1: ObjectWithRootPropertyNameFromList = { // okay
    Property1: 'foo',
};

const obj2: ObjectWithRootPropertyNameFromList = { // okay
    Property2: 'foo',
};

const obj3: ObjectWithRootPropertyNameFromList = { // error
    Property3: 'foo',
}; 

Upvotes: 1

Related Questions