Reputation: 2086
Is there a way to define a Typescript interface
which allows one of 2 optional keys in an object or none of them, but not both?
Here is a simplified example of what I'm trying to achieve:
const example1 = { foo: 'some string' }; //should pass - can have only "foo: string"
const example2 = { bar: 42 }; // should pass - can have only "bar: number"
const example3 = {}; // should pass - both foo and bar are optional
const example4 = { foo: 'some string', bar: 42 }; // should throw a Typescript error - can't have both foo and bar simultaneously;
PS. solution should be an interface
and not a type
since in my use-case it extends
another interface
Upvotes: 7
Views: 2687
Reputation: 20162
type
is isomorphic to interface
and you can join these two constructs. Below implementation by type union and intersection, also added example interface to show it works well, &
is equivalent to extends
. Consider:
interface OtherInterface {
field?: string
}
type Example = ({
foo: string
bar?: never
} | {
foo?: never
bar: number
} | {
[K in any]: never
}) & OtherInterface
const example1: Example = { foo: 'some string' }; // ok
const example2: Example = { bar: 42 }; // ok
const example3: Example = {}; // ok
const example4: Example = { foo: 'some string', bar: 42 }; // error
The solution is verbose, but match your need. Some explanations:
bar?: never
is used in order to block possibility to have a value which has such field& OtherInterface
has exactly the same result as extends OtherInterface
{[K in any]: never}
- represents empty object {}
Upvotes: 8