2

Say I have a typescript interface:

interface MyInputInterface {
  a: A | null
  b: B | null
  aString: string | null
}

This is what I have currently:

const hasOneNonNull = (input: MyInputInterface) => 
  input.a !== null || input.b !== null || input.aString !== null

But this seems very brittle. I have to remember to update the check everytime I add a new interface member. Is there a way to iterate through all the interface members and check that at least one of them is non null?

Something like this would be more ideal (getAllMembers is pseudocode):

const hasOneNonNull = (input: MyInputInterface) => 
  input.getAllMembers().find((elem: any) => any !== null) !== null
Arnab Datta
  • 5,356
  • 10
  • 41
  • 67
  • 1
    You can use [Object.values()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Object/values) if you are sure there is no additional member in your object. – Paleo Aug 20 '19 at 11:42

1 Answers1

4

You are looking for Object.values:

const hasOneNonNull = (input: MyInputInterface) =>
  Object.values(input).reduce((hasNonNull, value) => hasNonNull|| value !== null, false);

You can also leverage a union type to specify, that you require at least a or b:

type MyInputInterface =
  | { a: A; b: B | null; aString: string | null; }
  | { a: A | null; b: B; aString: string | null; }
  | { a: A | null; b: B | null; aString: string; }

The type can also be specified using Typescript's mapped types:

The following is taken from this SO answer:

interface FullMyInputInterface {
  a: A;
  b: B;
  aString: string;
}

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

type MyInputInterface = AtLeastOne<FullMyInputInterface>
DAG
  • 6,710
  • 4
  • 39
  • 63