Pick one type of an intersection type in typescript

Viewed 1394

I found myself in the following situation:

Having a variable of type A, I pass it to an API which returns a value of type A & B. I then have to post this returned value to an HTTP endpoint which expects a payload of type A.

interface A {
  name: string;
}

interface B {
  type: string;
}

function api(arg: A): A & B {
  return { name: arg.name, type: 'Blah' };
}

const x: A = { name: 'Foo' };

const y: A & B = api(x);

const z: A = y;

// Simulate HTTP call with payload z of type A
console.log(JSON.stringify(z));

The output is {"name":"Foo","type":"Blah"}. Although z is of type A, the payload still contains B's fields.

How can I remove one of the intersection types (B) and only keep type A so that the output would be {"name":"Foo"}?

1 Answers

Titian explained this pretty well, but unfortunately interfaces are compile time components and not run time, so these cases can be hard to account for. Using their solution, you could adapt it to your situation to get something like

function extract<T>(properties: Record<keyof T, true>) {
  return function <TActual extends T>(value: TActual): T {
    const result = {} as T;
    for (const property of Object.keys(properties) as Array<keyof T>) {
      result[property] = value[property];
    }
    return result;
  };
}

const extractA = extract<A>({
  name: true,
});

// { name: 'Foo' }
console.log(extractA(z));
Related