-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
Union not narrowed with typeof x.y
as a discriminant
#32399
Comments
typeof x.y === 'object'
with mixed primitive and nonprimitive discriminants
I'm not sure |
Just chiming in to say I would love this fixed! Our repro is something like the following: interface A { x: string, y: string };
interface B { x: number, y: number };
type X = A | B;
declare var bar: X;
if (typeof bar.x === 'string') {
let y = bar.y; // string | number, but really should be string.
} Essentially we have some methods we'd like to return union of object types from. The object types are mostly distinct with a little overlap. Ideally users would just check the field that they want is present, and TS would do the math and present a proper type inside the We ran in to this because we were using a tagged union pattern which was working fine, but then attempted to generalize it, and found the narrowing stopped working. |
typeof x.y === 'object'
with mixed primitive and nonprimitive discriminantstypeof x.y
as a discriminant
Looks interesting. I would have a try on this. |
Hi, if I define
What type of u and u.key should be? |
Maybe it should have comparable behavior to the literal type case? interface Foo1 {
key: "number" | "undefined";
f1: number;
}
interface Foo2 {
key: "string" | "undefined";
f2: number;
}
type U = Foo1 | Foo2
function f1(u: U) {
if (u.key !== 'number' && u.key !== 'undefined') {
u; // U
u.key; // 'string'
}
} |
I ran across this after seeing @jack-williams's comment here: #30622 (comment) I was trying to "entangle" the refinements on two types by sticking them in an object together and was surprised that it didn't work: function f(x: string | number, y: string | number) {
let o;
if (typeof x === 'string' && typeof y === 'string') {
o = { x, y };
} else if (typeof x === 'number' && typeof y === 'number') {
o = { x, y };
} else {
throw new Error(`Can't have mixed types: ${typeof x} and ${typeof y}`);
}
o; // type is { x: string; y: string; } |
// { x: number; y: number; }
o.x; // type is string | number
if (typeof o.x === 'string') {
o.x; // type is string
o; // type is the same as above
o.y; // type is string | number :(
}
} |
This would be useful to have since the improved tuple types in 4.0 will make overload implementations that use tuples even more common. function Example(a: number, b?: number): number;
function Example(a: string, b?: string): string;
function Example(...args: [a: number, b?: number] | [a: string, b?: string]): number | string {
if (typeof args[0] === 'number') {
// doesn't narrow
} else {
// doesn't narrow
}
} |
Is this a duplicate of #30506? For its case, #30506 (comment) explained that:
Although this issue involves |
Pulling in Ryan's comment from 2022 as the latest update on this issue #38839 (comment):
|
This was fixed in #50344, as far as I can tell. |
TypeScript Version: 3.6.0-dev.20190713
Search Terms:
TS2339
,union type object
,union type property does not exist
And github suggestions while I was writing the title.
Code
Expected behavior:
String in
someKeyThatExistOnlyIfOtherKeyIsNotFalse
should be loggedActual behavior:
Playground Link:
https://www.typescriptlang.org/play/index.html#code/C4TwDgpgBAKhDOwCMUC8UDeAoKurwHsBbCAaQhAC4oAzAQwBt4IsBfKAH0xz0JPKrc8w-MTIUAkgDt4ASwAmEalICuRAEYQATj1ysANLtH8KMABZ1gAUQAesxAHkpDEBJoPgZ7QInwAcgTAAGKMzNSIWrJSAOYA3GzxWIoAxgx0WtDJBDLAUMAIyNRwiEiJsjRQABT5JQB0fOIgAJRCeFkyBAwQtQwE0dUFSPViAuaWtvbATi5uHl5aPv6BIUwQTbFQAPSbUA6kAIRsWFigkLAFAExorbgNAtT0q2ycN8aN1NgieNuwXlDZLn+Umg8nKNG0ECkyWgNC0xDy4GgxWQ+jePhkCkydCkUE0UBUUkUNCiEHkQLRFCMwjukgxigA-Mo1JodMIDEYaSAxtY7I5nK53J5vJIlsFQkp8MBIjF4qxEik0hkoO1EHlLkVLmUKtVEQQKjVgBdhiYQGhUOgAOQEdQAKwgyWAFpanza2UIXR6fQGiCNnO5Ez5M0F80WATFq3WWx2MAAyhcAMzxgCc1AACnDIFpQFALX6LDzJtMBXNha5RStmBaoPICAgoFJAlAILzctkEWcLRgKYJHswNqwLbU2EA
Take a look at
type Test1
. The only one difference fromtype Test2
issomeKeyInside
should be always defined.Related Issues:
The text was updated successfully, but these errors were encountered: