0

I would like to create a fat-arrow function, that will return:

  • string, if the argument is a number,
  • number, if the argument is a string.

This is my code so far:

type ToString = (input: number) => string
type ToNumber = (input: string) => number
type Converter = ToString | ToNumber

const convert: Converter = <T extends number | string>(val: T) => null as any // The function body is not important.

const x = convert(7) // Error: Argument of type 'number' is not assignable to parameter of type 'never'. (2345)

Unfortunately, the code above doesn't work because of the mentioned error message on the last line. Is there any way to fix it?

Michal
  • 1,755
  • 3
  • 21
  • 53
  • 1
    Is this just a typo? You want `type Converter = ToString & ToNumber`, as it is both a `ToString` *and* a `ToNumber`. [Like this](https://tsplay.dev/WK7ZpW). If you write `ToString | ToNumber` it means that `convert` could be one *or* the other and you can't call it unless you know which one, or you manage to pass in a parameter that would work regardless, meaning a `number` *and* a `string`, or `number & string` which is impossible and reduces to `never`. – jcalz Dec 06 '21 at 03:59
  • If this is not just a typo then I can write up an answer explaining why you want an intersection of call signatures (equivalent to an overload) instead of a union of call signatures (which can be [called](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-3.html#improved-behavior-for-calling-union-types) but only with an intersection of function parameters). Of course you can also make a single generic/conditional call signature, but that might be out of scope for the question. Let me know what you want to see here. – jcalz Dec 06 '21 at 04:02
  • See [Typescript overload arrow functions](https://stackoverflow.com/questions/39187614/typescript-overload-arrow-functions) and [Can I use TypeScript overloads when using fat arrow syntax for class methods?](https://stackoverflow.com/q/20646171/12299000) – kaya3 Dec 06 '21 at 04:08

1 Answers1

2

Define it as generic type:

type Converter = <T extends string | number>(input: T) => T extends string ? number : string;

const convert: Converter = <T extends string | number>(val: T): T extends string ? number : string => null as any; // The function body is not important.

Or use overload:

function convert(val: string): number;
function convert(val: number): string;
function convert(val: string | number) {
  return null as any;
}
fixiabis
  • 363
  • 1
  • 8