Home > Mobile >  Typescript: How to know if a union type MIGHT contain a subset?
Typescript: How to know if a union type MIGHT contain a subset?

Time:01-24

I'm trying to type a function parameter where the param accepts any type where the union contains a known subset.

For example:

type One = { a: "one"; b: 1 };
type Two = { a: "two"; b: 2 };

type U = One | Two;

// `CouldContain` is some kind of wrapper that says it MIGHT contain `Two`
function test(param: CouldContain<Two>) {}

So the following would work:

const pass: U = { a: "one", b: 1 };

test(pass); // `U` contains `Two` 

And so would:

type Z = { } | Two

const pass: Z = { };
test(pass); // `Z` contains `Two`

But this wouldn't:

const fail = { a: "three", b: 3}

test(fail); // Not inferred as `Two`

Nor would:

const fail = { };

test(fail); // Valid branch of `Z` which contains `Two`, but no way to infer this as `Z` so it fails

The use-case I have is inferring whether dynamically generated GraphQL data types might contain a specific union type.

CodePudding user response:

What an odd question. Here is my approach.

type CouldContain<T, U> = Extract<T, U> extends never ? never : T

function test<T>(param: CouldContain<T, Two>) {}

This works by using the argument param to infer the generic type T and by using a conditional type to check if Two is a member of T.

When using this type, how have to note one important thing:

type U = One | Two;
const pass: U = { a: "one", b: 1 } as U;
test(pass); // ok

type Z = { } | Two
const pass2: Z = { } as Z;
test(pass2); // ok

const fail = { a: "three", b: 3}
test(fail); // fails

const fail2 = { };
test(fail2) // fails

The two type assertions as U and as Z are needed for this to work. Control flow analysis will otherwise use the literal type to attach invisible type information to pass and pass2. Without the type assertions the compiler slightly changes both types, so that Two is not part of their union anymore. The type assertions will stop the compiler from doing these optimizations.


Playground

CodePudding user response:

I recommend you to check the following URL content out: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/has

  • Related