0

When you use Partial<SomeType>, technically an empty object satisfies that typecheck. Is there a way to exclude that?

    interface MyType {
        foo: string
        bar: string
    }

    function someFunction(obj: Partial<MyType>) {
        // whatever
    }

    someFunction({}) // ideally, I would like this should throw a type error
Joseph
  • 33
  • 1
  • 6

2 Answers2

9

Greatly inspired by this answer (which also explains how it works in detail), here's what you'll need:

type AtLeastOne<T, U = {[K in keyof T]: Pick<T, K> }> = Partial<T> & U[keyof U];

And then use this new type instead of Partial.

Playground

lukasgeiter
  • 147,337
  • 26
  • 332
  • 270
1

If your type is simple, one option is to define all the valid cases. If it's a complex type, this might not be maintainable.

type MyType = { foo: string } | { bar: string } | { foo: string; bar: string; }

function someFunction(obj: MyType) {}

someFunction({ foo: "baz" }); // valid
someFunction({ bar: "baz" }); // valid
someFunction({ foo: "baz", bar: "baz" }); // valid
someFunction({}); // error

TypeScript playground

Another solution is shared in this answer: https://stackoverflow.com/a/49725198/2690790

type RequireAtLeastOne<T, Keys extends keyof T = keyof T> = Pick<
  T,
  Exclude<keyof T, Keys>
> &
  {
    [K in Keys]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<Keys, K>>>
  }[Keys];

interface MyType {
  foo: string;
  bar: string;
}

function someFunction(obj: RequireAtLeastOne<MyType>) {}

someFunction({ foo: "baz" }); // valid
someFunction({ bar: "baz" }); // valid
someFunction({ foo: "baz", bar: "baz" }); // valid
someFunction({}); // error

TypeScript playground

skovy
  • 5,430
  • 2
  • 20
  • 34
  • Ya, I've done this for simple types when the number of possibilities for finite. But as you mentioned, this isn't possible pragmatic when working with more complex or generic types. – Joseph Sep 05 '19 at 04:01