Search code examples
typescripttypesstatic-analysistypechecking

Typescript type requiring any one attribute of an object to be defined: how?


I have the following TypeScript code:

interface qux {
    foo?: string;
    bar?: number | string;
}

function foobar(x: qux) { ...; something_frobz(x); ...; }

Problem: I can call foobar("hello, world"), even though this causes something_frobz to misbehave. I would like to catch and reject calls to foobar with string argument at compile time, while altering the structure of qux as little as possible. What's the best way of going about this?

My own solution is to make one field required; that field has a sensible default value, and AFAIK string doesn't have any fields with the same name. That's a bit of a hack, but it works.

Another approach might be to have foobar take a union type of first-field-is-required | second-field-is-required | ... | hundredth-field-is-required, but then I have to maintain N almost-identical copies of qux (for N > 1) and that never goes well.

Is there anything better?


Solution

  • Typescript version 2.2 - 2.3

    To prevent passing "primitives" as a parameter, you can require it to be an object:

    function foobar(x: qux & object) { }
    
    foobar(''); //error
    foobar(1); //error
    foobar({a:1}); //error
    
    foobar({foo:'bar'}); //ok
    

    Typescript version >= 2.4 object constraint is not required anymore. See @dbandstra's answer for more information.