You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is the behavior in every version I tried, and I reviewed the FAQ for entries about union.
Have checked with Nightly, TS 4 versions and TS 3 versions.
interfaceIContainer<T,V>{key: T;value: V;}interfaceITypeA{existsOnA: string;}interfaceITypeB{existsOnB: number;}typeContainerUnion=IContainer<["A"],ITypeA>|IContainer<["B"],ITypeB>;functiontest(arg: ContainerUnion): void{};// ✔ - Passes as expectedtest({key: ["A"],value: {existsOnA: "HELLO"}});test({key: ["B"],value: {existsOnB: 0}});// ✔ - Errors as expectedtest({key: ["A"],value: {existsOnB: 0}});test({key: ["B"],value: {existsOnA: "HELLO"}});test({key: ["A"],value: {existsOnA: "",nonexistentProp: ""}});// ❌ - Problematic scenario - No errors, but would expect it to.test({key: ["A"],value: {existsOnA: "HELLO",existsOnB: 0}});
🙁 Actual behavior
No type error is occurring for
test({key: ["A"],value: {existsOnA: "HELLO",existsOnB: 0}});//existsOnB does not exist within IContainer<["A"], ITypeA>, but does on IContainer<["B"], ITypeB>.
When matching a type in a union using a nested Tuple or Object for generics, it treats properties as if they are a combination of the different types.
In the example above, once it matches the key, the type for value essentially becomes an intersection of the inferred value and partial of all the other permutations.
In essence this
IContainer<["A"], ITypeA> OR IContainer<["B"], ITypeB>;
is being treated as if it was this
IContainer<["A"], ITypeA & Partial<ITypeB>> OR IContainer<["B"], ITypeB & Partial<ITypeA>>;
(you can add more properties onto ITypeB to see this in action)
due to existsOnB not being present on the matched part of the union - IContainer<["A"], ITypeA>.
🗒 Notes
The behavior is currently inconsistent.
It will prevent non-existent properties from being valid.
It will prevent only properties from other values being valid.
e.g. test({ key: ["A"], value: { existsOnB: 0 } }); //Errors as expected
It will allow a partial of the other values.
It will work perfectly as expected when the first generics in the union which get matched are primitives (see line 65 onwards of the TS playground link above)
Snippet of a currently working scenario (TS version 4.6):
typeSimpleContainerUnion=IContainer<"A",ITypeA>|IContainer<"B",ITypeB>;//Every usage permutation of this works fully as expected.functiontest(arg: SimpleContainerUnion): void{};test({key: "A",value: {existsOnA: "HELLO",existsOnB: 0}});//Works fine - Type error as expected 🎉
I've tried to do a fair bit of digging throughout issues and the documentation, but have not yet come across something which shines a light on this behaviour.
Considering a union of IContainer<"A", ITypeA> | IContainer<"B", ITypeB> works for all scenarios, but IContainer<["A"], ITypeA> | IContainer<["B"], ITypeB> or even IContainer<{ type: "A" }, ITypeA> | IContainer<{ type: "B"}, ITypeB> does not, it feels like a bug.
Apologies if this is a known limitation or bug and I missed it in my earlier searches!
If it is a limitation, a simple explanation or pointer to documentation would be very much appreciated.
The text was updated successfully, but these errors were encountered:
Bug Report
🔎 Search Terms
🕗 Version & Regression Information
Have checked with Nightly, TS 4 versions and TS 3 versions.
⏯ Playground Link
Playground link with relevant code
💻 Code
🙁 Actual behavior
No type error is occurring for
When matching a type in a union using a nested Tuple or Object for generics, it treats properties as if they are a combination of the different types.
In the example above, once it matches the
key
, the type forvalue
essentially becomes an intersection of the inferred value and partial of all the other permutations.In essence this
is being treated as if it was this
(you can add more properties onto ITypeB to see this in action)
🙂 Expected behavior
A type error should be thrown for
due to
existsOnB
not being present on the matched part of the union -IContainer<["A"], ITypeA>
.🗒 Notes
The behavior is currently inconsistent.
It will prevent non-existent properties from being valid.
It will prevent only properties from other values being valid.
e.g.
test({ key: ["A"], value: { existsOnB: 0 } }); //Errors as expected
It will allow a partial of the other values.
It will work perfectly as expected when the first generics in the union which get matched are primitives (see line 65 onwards of the TS playground link above)
Snippet of a currently working scenario (TS version 4.6):
I've tried to do a fair bit of digging throughout issues and the documentation, but have not yet come across something which shines a light on this behaviour.
Considering a union of
IContainer<"A", ITypeA> | IContainer<"B", ITypeB>
works for all scenarios, butIContainer<["A"], ITypeA> | IContainer<["B"], ITypeB>
or evenIContainer<{ type: "A" }, ITypeA> | IContainer<{ type: "B"}, ITypeB>
does not, it feels like a bug.Apologies if this is a known limitation or bug and I missed it in my earlier searches!
If it is a limitation, a simple explanation or pointer to documentation would be very much appreciated.
The text was updated successfully, but these errors were encountered: