-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Discriminated union Key-Types #12448
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
So what happens here is that we try to infer a type for What you want here is for the second parameter's use of An alternative typing which is better for callers but worse for the implementer is: function updateUniform<V, T extends { tag: GLUniform['tag'] , value: V }> ( u: T, t: V ) {
switch ( u.tag ) {
// update the value stored in GPU memory
}
} Luckily you can have your caller signature and implementation signature be different, so you can write this and get the best of both worlds: function updateUniform<V, T extends { tag: GLUniform['tag'] , value: V }> ( u: T, t: V ) {
function updateUniform(u: GLUniform, v: GLUniform['value']) {
// ... |
This can be simplified to use overloads with no generic types as such: type Tag1 = { tag: 'F', value: number };
type Tag2 = { tag: 'F2', value: number[] };
type GLUniform = Tag1 | Tag2;
declare function updateUniform(t: Tag1, v: Tag1["value"]);
declare function updateUniform(t: Tag2, v: Tag2["value"]); but regardless, i think there is an issue with when the constraint is instantiated. i would have expected this to work in the same way: declare function updateUniform<T extends GLUniform, V extends T['value']>(t: T, v: V); since we would infer for |
@RyanCavanaugh thanks for the help I was able to get your first option to work ( worse for the implementor ) but I'm a little unclear on your second comment. How do I specify these two sigs? One w/o a body an the implementor w/ a body? @mhegazy Thanks very much for you followup. Your idea is precisely what I thought of when I realized that TS did have a mechanism for function overloading ( on discriminated union-members in this case ) but as you can see in the code below, I am probably missing something. When I try to compile this code it complains that the type interface F { tag: 'F', value: number }
interface F2 { tag: 'F2', value: number[] }
type GLT = F | F2
function update ( u: F, v: F['value'] ): void
function update ( u: F2, v: F2['value'] ): void
function update ( u: GLT, v: GLT['value'] ) {
switch ( u.tag ) {
case 'F': return console.log(u.value + v)
case 'F2': return console.log(v)
default: const n: never = u
return n
}
}
update({ tag: 'F', value: 5 }, 3)
update({ tag: 'F2', value: [ 5 ] }, [ 2 ])
// update({ tag: 'F2', value: [ 5 ] }, 2)
// matches({ tag: 'F2', value: [ 5 ] }, 2) If I relax the generic signature as follow: function update ( u: GLT, v: any ) then it works as expected an gives access to number addition and vector concatenation respectively after switch-discrimination. |
The issue is var u: GLT;
var v = u.value;
switch (u.tag) {
case 'F': console.log(u.value + v) // u.value is number, but v is number|number[]
case 'F2': console.log(v)
} tracking aliases and narrowing them is not a simple thing to do. |
I have started using class-based polymorphism and methods to solve this problem. It's a sort of poor-man's typeclass solution that allows me to constrain polymorphism to instances which are defined ( extensible and not limited to the weirdness of overloaded function signatures ) |
Happy to report that this errors as expected now |
TypeScript Version: 2.2.0-dev.20161122
Code
Expected behavior:
updateUniform({ tag: 'F2', value: [ 1, 2 ] }, 5 )
should fail to compile because the type of value for 'F2' is number[] and not number.Actual behavior:
It seems that U['value'] is unioning all the possible values of
value
for all types in the discriminated union. I would expect it to understand that the value must match the type of "value" key for the given candidate value of GLType ( in this case, { tag: 'F2', value: number[] } )The text was updated successfully, but these errors were encountered: