1

I have a situation like this:

interface Foo {
  a: { name: string };
  b: { x: number; y: number };
}

const obj: Foo = createFoo();
const member = obj[Math.random() > 0.5 ? "a" : "b"];

Here, TypeScript correctly infers that the type of member should be { name: string } | { x: number; y: number }. But, say I want to do something like this:

handleFooMember(member);

function handleFooMember(member: /* what type do I put here? */) {
  if ("name" in member) {
    console.log(member.name);
  } else {
    console.log(member.x, member.y);
  }
}

How do I type that function so that the member argument could be any field of Foo? Obviously, I could hard-code that union type ({ name: string } | { x: number; y: number }). But if Foo has a lot of complex fields or I might add more fields later on, that's not ideal.

Is there a typescript way to express the idea of "Any of the field of this type"? Something like Union<Members<Foo>>?

QuinnFreedman
  • 2,242
  • 2
  • 25
  • 42
  • You're looking for `Foo[keyof Foo]`, using [indexed access types](https://www.typescriptlang.org/docs/handbook/2/indexed-access-types.html). Looks like a duplicate of https://stackoverflow.com/q/49285864/2887218 – jcalz Mar 04 '22 at 20:31
  • @jcalz Thanks I think you're right. I'll mark as duplicate – QuinnFreedman Mar 04 '22 at 20:33

1 Answers1

2

The typical approach is:

function handleFooMember(member: Foo[keyof Foo]) {
  ...
}
tokland
  • 66,169
  • 13
  • 144
  • 170