0

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 ▶

1 Answer 1

1

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>);
}
Sign up to request clarification or add additional context in comments.

5 Comments

That's not it unfortunately. I tried that. If you click on 'Playground ▶' you can play around with the error.
Thanks for having a look with me! Technically this works, but I still feel like there is a gotcha that I'm missing, since it's quite verbose / feels unnecessary.
This is the right procedure although the answer should maybe be edited to explain what's happening: the compiler cannot usually verify assignability to unspecified generic types, especially conditional types that depend on unspecified generic type parameters. If T were some specific type, the compiler could evaluate FuncArg<T>, but since it's a generic type parameter, the compiler defers evaluating it until later. So it won't know if {item: item}is or is not assignable because it doesn't know what T is. There are github issues about this, let me see if I can find some

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.