Search code examples
typescripttypesunion-types

Configure a TypeScript type for an object to have at least 1 of any specific keys


This question is kinda difficult for me to explain and thus difficult for me to find a definitive answer for.

I have the below code:

type myType = {
    apple ?: any
    banana ?: any
}

const sample = function(myObject : myType) {
    if (typeof myObject.apple !== 'undefined' || typeof myObject.banana !== 'undefined') {
        // Do something
    } else {
        // This will cause an error!
    }
}

sample({ apple: true }) // This is good
sample({ banana: 'hello world' }) // This is good
sample({ apple: false, banana: 'foo bar' }) // This is good
sample({}) // This is NOT good
sample({ banana: undefined }) // This is NOT good
sample({ taco: 'hello world' }) // This is NOT good

I am trying to make a type that can detect the "NOT good" cases

My Question: How can I modify myType to trigger an error when all of its keys are not set but not when at least 1 of its known keys are set?


On a side note: I think I can do the below, but it seems very inelegant and probably a poor programming practice. I would prefer an alternate solution because my real code has dozens of keys and would be more than a little tedious.

type myType_1 = {
    apple : any
    banana ?: any
}
type myType_2 = {
    apple ?: any
    banana : any
}
type myType = myType_1 | myType_2

Solution

  • You can do this with a helper type: TS Playground

    type OneOf<T> = {
      [K in keyof T]-?: Pick<T, K> & Partial<T>
    }[keyof T]
    

    Note that for this to detect the sample({ banana: undefined }) case, the type of banana must not be any since undefined is assignable to any.