0

I'm trying to understand how function overloading in typescript works.

type CreateElement = {
  (tag: 'a'): HTMLAnchorElement
  (tag: 'canvas'): HTMLCanvasElement
  (tag: 'table'): HTMLTableElement
}

let createElement: CreateElement = (tag: 'a' | 'canvas' | 'table') => {
  if (tag === 'a') return new HTMLAnchorElement()
  if (tag === 'canvas') return new HTMLCanvasElement()
  if (tag === 'table') return new HTMLTableElement()
  throw new Error('wrong tag');
}

The code above throws the error:

Type 'HTMLAnchorElement | HTMLCanvasElement | HTMLTableElement' is not assignable to type 'HTMLAnchorElement'.
    Type 'HTMLCanvasElement' is missing the following properties from type 'HTMLAnchorElement': charset, coords, download, hreflang, and 21 more.

I have ensured that I resolve the parameter tag before returning the appropriate type for a given tag type. Any ideas why this doesn't work?

quantdaddy
  • 1,375
  • 4
  • 19
  • 29
  • Wouldn't `CreateElement` be `type CreateElement = HTMLAnchorElement | HTMLCanvasElement | HTMLTableElement`? – Brandon Dyer Jan 27 '20 at 22:40
  • Not sure what you mean, I'm overloading the function by taking union of function signature but you're referring to union of objects. – quantdaddy Jan 27 '20 at 22:45

1 Answers1

1

Function overloads can only be used with function declarations.

Workarounds with "overloaded" (arrow) function expressions may work in a limited, weak typed way. But unlike the former, the compiler does not have a special treatment for these expressions. So they will not behave in the manner you expect it (your code error is already a good example).

Your rewritten example with proper function overloads looks like this:

function createElement(tag: 'a'): HTMLAnchorElement // overload 1
function createElement(tag: 'canvas'): HTMLCanvasElement // 2
function createElement(tag: 'table'): HTMLTableElement // 3 
function createElement(tag: 'a' | 'canvas' | 'table') { // fn implementation
    if (tag === 'a') return new HTMLAnchorElement()
    if (tag === 'canvas') return new HTMLCanvasElement()
    if (tag === 'table') return new HTMLTableElement()
    throw new Error('wrong tag');
}

const ret = createElement("a") // HTMLAnchorElement
ford04
  • 66,267
  • 20
  • 199
  • 171
  • I see...this works. Only drawback is the need to repeat the function name compared to function expression. – quantdaddy Jan 27 '20 at 23:35
  • yeah, I also like the leaner arrow function syntax a bit more (and you can declare function interface types for them). But this one will provide stronger types for the function implementation. So I would prefer it anytime. – ford04 Jan 28 '20 at 07:35