Gersom
Gersom

Reputation: 671

TypeScript generics and function parameter conditional types

Let's say I have a function that returns the return value of a passed-in getIdentifier function. This function is mandatory, except for when the item has an id property because I can fall back to reading just that.

type FuncArg<T> = T extends { id: string }
  ? { item: T; getIdentifier?: (item: T) => string }
  : { item: T; getIdentifier: (item: T) => string };

type withId<T> = T & { id: string };

const getFoobar = <T>(arg: FuncArg<T>) => {
  return arg.getIdentifier ? arg.getIdentifier(arg.item) : (arg.item as withId<T>).id;
};

All well so far. Let's say I have a second function that passes in an item to the first function, checks if it has an id and if not it passes in a random generator getIdentifier.

const getFoobar2 = <T>(item: T) => {
  if ('id' in item) return getFoobar({item: item as withId<T>});
  return getFoobar({item: item, getIdentifier: () => Math.random().toString()});
}

Unfortunately the typechecking breaks in the last example and I have no idea to fix this. I've tried everything from conditional types to union types and function overloads. Everytime I run into similar problems. What am I missing here?

Playground ▶

Upvotes: 0

Views: 173

Answers (1)

Yehor Androsov
Yehor Androsov

Reputation: 6152

You missed item parameter in getIdentifier function signature and looks like it requires explicit as FuncArg<T> in object declaration. Can't explain better, don't have much experience in Typescript.

const getFoobar2 = <T>(item: T) => {
  if ('id' in item)
    return getFoobar({ item: item } as FuncArg<T>);
  return getFoobar({item: item, getIdentifier: (item: T) => Math.random().toString()} as FuncArg<T>);
}

Upvotes: 1

Related Questions