12

I'd like to type an object that can contain any property, but if it has any of the properties a, b or c, it must contain all of the properies a, b and c.

In other words: the object can contain any property, but if it contains a, b or c it must contain a, b and c.

let something: Something;

// these should be valid:
something = { a: 1, b: 1, c:, 1 };
something = { a: 1, b: 1, c:, 1, custom: 'custom' };
something = { custom: 'custom' };

// these should be invalid:
something = { a: 1 };
something = { a: 1, b: 1 };
something = { a: 1, c: 1 };
something = { b: 1 };
something = { a: 1, custom: 'custom' };

How can this be achieved?

Creating a union type with an object seems correct, but doesn't work:

interface RequiredProps {
    a: number;
    b: number;
    c: number;
}

type Something = RequiredProps | {};
1
  • probably it is better to have union of two types or even just any and then use type check to limit type to something concrete. Commented Mar 13, 2018 at 20:23

1 Answer 1

16

You can create a union type, between a type that allows a, b, c and an indexer, and one that forces a, b, and c if present to have type never.

 type Something = ({ a: number, b: number, c: number } & { [n: string]: any }) |
    ( { a?: never, b?: never, c?: never } &{ [n: string]: any });

If you have functions that return never it may be possible to assign the properties but for most practical cases this should work.

We could even create a generic type for this situation:

type RequireAll<TOptional, TRequired> = (TOptional & TRequired) | (Partial<Record<keyof TOptional, never>> & TRequired)
type Something = RequireAll<{a: number, b: number, c:number}, {[n:string]:any}>
Sign up to request clarification or add additional context in comments.

2 Comments

These TOptional and TRequired sound confusing, I'd suggest the wording T and TAllOrNone instead: export type AllOrNone<T, TAllOrNone> = (T & TAllOrNone) | (T & Partial<Record<keyof TAllOrNone, never>>);
Works fine when the initializing the variable but looks like now working when trying to discriminate the specific subtype... I'll prepare the separate question.

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.