-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Using string literal types to distinguish overloads - Advanced Types Section - String Literal Types Subsection #235
Comments
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 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 |
Actually, I'm going to reopen this issue. You're definitely not the only one who's going to run into this. |
class A {
x:number;
}
class B {
y:number;
}
type z = "a" | "b"
function f(x:string, obj:A | B);
function f(x:"a", obj:A);
function f(x:"b", obj:B);
function f(x:string, obj:A | B){
if (x === "a") {
obj.x = 1;// point 1 <-------- code completion
} else if (x === "b") {
obj.y = 1;// point 2 <-------- code completion
} else {
}
} 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? |
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: function isA(tag: "a" | "b", obj: A | B): obj is A {
return tag === "a";
}
function isB(tag: "a" | "b", obj: A | B): obj is B {
return tag === "b";
}
function f(x: "a", obj: A);
function f(x: "b", obj: B);
function f(x: "a" | "b", obj: A | B){
if (isA(x, obj)) {
obj.x = 1;
}
else if (isB(x, obj)) {
obj.y = 1;
}
else {
throw "wat";
}
} Or in 2.0 beta, you can just add the tags to |
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. function f(x: "x1", y:"y1"|"y2", z:"z1"|"z2", obj: X1);
function f(x: "x1"|"x2", y:"y1", z:"z1"|"z2", obj: Y1);
function f(x: "x1"|"x2", y:"y1"|"y2", z:"z1", obj: Z1);
function f(x:"x1"| "x2", y: "y1"|"y2", z:"z1"|"z2") {
... a lot of combinatoric stuff to analyze goes to here
} |
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. |
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:
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
.2- Define an overload that takes a
string
type of the function that already takes astring
.Is this a handbook code error or a compiler error and the code in the handbook is correct?
The text was updated successfully, but these errors were encountered: