asserts this is T does not narrow type of this #60140
Copy link
Copy link
Open
Labels
Cursed?It's likely this is extremely difficult to fix without making something else much, much worseIt's likely this is extremely difficult to fix without making something else much, much worseDomain: This-TypingThe issue relates to providing types to thisThe issue relates to providing types to thisPossible ImprovementThe current behavior isn't wrong, but it's possible to see that it might be better in some casesThe current behavior isn't wrong, but it's possible to see that it might be better in some cases
Milestone
Description
🔎 Search Terms
asserts this is Tnarrowassertions- I also checked Unions of assertion functions do not act as assertion functions #59707, but it is unrelated (generic types).
🕗 Version & Regression Information
- Playground:
v5.7.0-dev.20241004 - At least since
v5.6.2
⏯ Playground Link
💻 Code
class A {
onlyDefinedInA() {
console.log("A");
}
assertA(): asserts this is A { }
}
class B {
assertA(): asserts this is A { }
}
type C = A | B;
function assertA(c: C): asserts c is A {
}
function test1(c: C) {
c.assertA();
c.onlyDefinedInA(); // Error: Property 'onlyDefinedInA' does not exist on type 'C'. Property 'onlyDefinedInA' does not exist on type 'B'.
}
function test2(c: C) {
assertA(c);
c.onlyDefinedInA(); // Works!
}🙁 Actual behavior
Type of c is not narrowed after the method call, producing an error.
🙂 Expected behavior
I expect the member function to to perform type narrowing.
Additional information about the issue
No response
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
Cursed?It's likely this is extremely difficult to fix without making something else much, much worseIt's likely this is extremely difficult to fix without making something else much, much worseDomain: This-TypingThe issue relates to providing types to thisThe issue relates to providing types to thisPossible ImprovementThe current behavior isn't wrong, but it's possible to see that it might be better in some casesThe current behavior isn't wrong, but it's possible to see that it might be better in some cases
Activity
remove `assertIsX()` for variants
Andarist commentedon Oct 4, 2024
It's still related - the generic types used there are red herring, the issue described there is not specific to them. See my comment in that issue, you have the same situation here - when the compiler sees a union it tries to create a composite signature from all of the constituents of that type. That process deliberately skips assertions.
OmarTawfik commentedon Oct 5, 2024
Mateusz Burzyński (@Andarist) I see. Thanks for confirming.
Is there a technical reason that prevents the compiler from making it work? or is it just not implemented yet?
If it was the former, then I think it should be an explicit error, to save future users time debugging/root causing this like I did.
If it was the latter, then I suggest keeping the issue open, and maybe adding a few pointers on how to go about fixing it.
RyanCavanaugh commentedon Oct 16, 2024
Not quite sure what to do with this.
It's obviously safe to maintain the predicateness when the asserted type in every signature is identical.
But only identical identical (i.e. mutual subtyping is not sufficient) is safe to do that, and we run into problems when we expose "identity" as a concept because you run into problems, e.g. if instead you had written
then this "wouldn't work" and we get bug reports that "X1 and X2 are identical" for some definition of "identical" and it just looks like a different kind of bug.
Or, worse, people start writing new cursed variants of
IsEqual<T1, T2>and later when we fix this in some as-yet-undiscovered better way, we break that utility type.So anyway I don't disagree it's suboptimal, but I am really not convinced that any known cure is better than the disease in this situation.
booleanis still a sound inference here.OmarTawfik commentedon Oct 17, 2024
Ryan Cavanaugh (@RyanCavanaugh) thanks for the detailed follow up!
In that case, at least until there is a better/future-proof way to support this, I wonder if it can be an explicit error in the meantime, to save future users time debugging/root causing this like I did. Unfortunately the current type information surfaced in the IDE indicates it should succeed (playground link above):
SebastienGllmt commentedon Dec 7, 2024
This is related to #28159
you can't change the value of a variable partway through a function. For the same reason that
you also get that
I agree it's unfortunate since this would be a useful functionality for builders so you don't have to construct a builder in one giant chain
JounQin commentedon May 14, 2025
A similar issue:
playground
Andarist commentedon May 14, 2025
JounQin (@JounQin) This one is a different issue. The original issue here is strongly related to unions. You are mixing a private and public
amembers in that intersection and that reduces the containing type tonever. This works as expected.JounQin commentedon May 14, 2025
Mateusz Burzyński (@Andarist) Seems reasonable, thanks. Updated playground with public member.
But is that possible to make my issue work as expected without mark
aaspublic?Andarist commentedon May 14, 2025
I don't think so. You can't have an overlapping public member with a private one of the same name.
JounQin commentedon May 14, 2025
That's really an unfortunate limitation then. :(
lxmfly123 commentedon Jun 28, 2026
I tried this.
assignworks perfectly, butremovecannot narrow type ofthis.