This repository was archived by the owner on Oct 12, 2022. It is now read-only.
This repository was archived by the owner on Oct 12, 2022. It is now read-only.
Using string literal types to distinguish overloads - Advanced Types Section - String Literal Types Subsection #235
Open
Description
Obviously the code in the handbook about using string literal types to distinguish overloads doesn't work out of the box, so I did my own tests using this code which looks like the one in the handbook:
class Element_ {
}
class HTMLImageElement_ extends Element_ {
constructor() {
super();
}
}
function createUIElement(tagName: "img"): HTMLImageElement_;
function createUIElement(tagName: string): Element_ {
switch (tagName) {
case 'img':
return new HTMLImageElement_();
default:
return new Element_();
}
}
The code above doesn't compile. VS Code will show the following compile error:
"Specialized overload signature is not assignable to any non-specialized signature."
I found two ways to fix this:
1- Use the default way of overloading and make a function that takes any
.
function createUIElement(tagName: "img"): HTMLImageElement_;
function createUIElement(tagName: string): Element_;
function createUIElement(tagName: any): Element_ {
switch (tagName as string) {
case 'img':
return new HTMLImageElement_();
default:
return new Element_();
}
}
2- Define an overload that takes a string
type of the function that already takes a string
.
function createUIElement(tagName: "img"): HTMLImageElement_;
function createUIElement(tagName: string): Element_; // if we remove this overload, we get the compile error
function createUIElement(tagName: string): Element_ {
switch (tagName) {
case 'img':
return new HTMLImageElement_();
default:
return new Element_();
}
}
Is this a handbook code error or a compiler error and the code in the handbook is correct?
Activity
DanielRosenwasser commentedon Apr 9, 2016
It used to be the case that a "specialized" overload (one that has a parameter whose type is a string literal) needed to be assignable to some non-specialized overload.
The solution you found in (2) is the one we usually recommend, since it looks like you were forgetting to provide a general overload anyway (i.e. you could never call this with a random
string
because you didn't have an overload that just takesstring
).In TypeScript 2.0, this will be fixed (see microsoft/TypeScript#6278). However, be careful, because this old check was the only thing that reminded you to provide the overload that just takes a
string
.DanielRosenwasser commentedon Apr 9, 2016
Actually, I'm going to reopen this issue. You're definitely not the only one who's going to run into this.
olegdunkan commentedon Aug 3, 2016
We know at point 1 that obj has type A, and we know at point 2 that obj has type B, how about type completion in these points?
DanielRosenwasser commentedon Aug 4, 2016
The type system doesn't work to reconcile implementation signatures with overload signatures. There's no obvious way to do so right now.
You can use type predicates to model this instead:
Or in 2.0 beta, you can just add the tags to
A
&B
themselves: https://twitter.com/drosenwasser/status/744243827158835200olegdunkan commentedon Aug 5, 2016
Of course an answer to the question about why there is no obvious way to do so is out of the scope of this thread. But it would be nice to understand why not obvious. Thanks.
My view of the problem is about multiple parameters.
Suppose we have
DanielRosenwasser commentedon Aug 5, 2016
It's partially about the combinatoric nature of overloads. It's also just in need of a proposal with how the type system works today. Simply unioning the types of each parameter seems easy enough, but it's not clear how helpful that would be, because in your use-case, you wanted to be able to relate each of the parameter types back to the original overloads. I've considered this problem and I'm not sure how we'd go about doing so in a clean & reasonable way.