-
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
Indirect type narrowing via const
#12184
Comments
This would require us to track what effects a particular value for one variable implies for other variables, which would add a good deal of complexity (and associated performance penalty) to the control flow analyzer. Still, we'll keep it as a suggestion. |
Thanks, @ahejlsberg, I appreciate the feedback and understand the complexities. |
I believe. :| |
Any progress on this? Really annoying to deal with. |
How is this issue looking right now? I think I have a similar problem and every other issue was linking to this one. If I have a condition the types are working correctly, but when I extract it into variable I get a TS error: Object is possibly 'undefined'. type Config = {
limit?: number;
offset?: number;
}
const showPagination = ({limit, offset}: Config) => {
const isPagination = limit && limit > 0 && offset && offset >= 0
// Doesn't work?!
if (isPagination) {
return limit * offset;
}
// Works!
if (limit && limit > 0 && offset && offset >= 0) {
return limit * offset;
}
return null
} Or check this playground: https://tinyurl.com/y7nrawkh |
to even simplify you can change it to const isPagination = typeof offset === 'number' && typeof limit === 'number'; |
Yep, I think that's this particular issue. I raised a similar one which was marked as a duplicate of this issue. |
|
I just stumbled across this and I'm wondering what puzzle pieces are missing to support this at least for single variables. Given that there is now the possibility to have custom type guards (functions with a return type of interface Square {
kind: "square";
size: number;
}
interface Rectangle {
kind: "rectangle";
width: number;
height: number;
}
type Shape = Square | Rectangle;
function isSquare(s: Shape): s is Square {
return s.kind === 'square';
}
function area(s: Shape) {
if (isSquare(s)) { // works
return s.size * s.size;
} else {
return s.width * s.height;
}
} couldn't it be possible to use this special type for variables too? For example like this: // ... other definitions like above
function area(s: Shape) {
const isSquare: s is Square = s.kind === 'square';
if (isSquare) {
return s.size * s.size;
} else {
return s.width * s.height;
}
} Based on my limited understanding of the TypeScript internals, this example doesn't seem fundamentally different from the case where a type guard function is called. Maybe it would even be possible to infer the type |
It would more likely infer: |
I agree with @ronaldruzicka that the I agree with the proposal from @AlCalzone as a stop gap because it retains almost all the brevity of the original ask by @gasi and may address a good part of the objection by @ahejlsberg that it'd require flow analysis; it doesn't appear structurally different to the function case at least when the I also believe that for TypeScript to live up to its promise, it needs to bite the bullet and do flow analysis. It's at a point of maturity, being worked on since 2012. Many closely related tools including TS tools themselves already engage in various ways of flow analysis. TypeScript maintaining this gap promotes poor coding practices, because one can't extract and name (sometimes common) constants, which is one of the most basic tools for readable, maintainable and efficient code. The decision process around TypeScript evolution comes into question, based on this issue and other issues where TS is also a leaky, non-contiguous abstraction, eg. the claim is structural typing, yet extra properties of objects most often fly under the radar (except with literals, an unexpected counterexception within the exception), despite it impacts structure just as much as missing properties do. TypeScript has leapt ahead in many esoteric, rarely used directions, while the basic quilt has gaps. One of the biggest is, lack of nominal typing, one can add angles in radians with angles in degrees because Prompted by this issue, I kindly ask for an executive revision of TypeScript toward the effect of enumerating and prioritizing issues, most of them with a history of so many years, so that its adoption is not hampered by such behaviors that are counterintuitive and/or TypeScript has grown a lot, it'd be useful to take a breath, look back and marvel at the amazing progress, and finally complete the basics for a tight, homogeneous baseline strength, while also reducing many of the pain points in the learning curve of TS, many of them caused by incidental rather than essential complexity, or suboptimal prioritization of solving gaps, an example for which is this one, four years and counting. TS has more potential to fill than this. |
@AlCalzone I (personally think) that having |
This is a very confused interpretation of history and the current state of reality. TypeScript has always had structural subtyping, but detecting excess properties in object literals was a very-frequently logged issue before that behavior existed (see #391 and its many incoming duplicates). This feature was implemented to much positive feedback at the time, and the behavior prior to excess property checking was widely cited as one of TS's worst shortcomings. To say that we're not paying attention to unexpected behavior by citing one of the most-requested changes we ever had (as measured by the proportion of feedback from users at the time) is a paradox. |
@RyanCavanaugh (I know that I just came in on this discussion and was mostly directed here from #24865). Do you see a future of having user type predicates having more then just one level of propagation? |
@RyanCavanaugh thanks for your reply,
Sorry for being unclear, I agree this behavior is the expected thing, also a step toward completing structural typing, worth extending it for non-literals too. There'd be a way to signal intent for additional keys, maybe named after Common Lisp's Yet, literals excess props check fragmented the behavior into two parts. This split behavior, which makes TS a tad more complicated, was my only reason for citing it. In the current case, the split is between inline use vs. binding to a variable name. TS thus weakens referential transparency; the extracted out way has no type assurance while inline use does. Steepened learning curve; hard to read code; denied refactoring options. Evolving TS must be incredibly hard, given all constraints, starting with JavaScript. Having said this, orthogonality is key to learning and using a language. It contrasts with the accreting, discursive, historical, accidental path of eg. philosophy, or ambiguities, special cases and reinvention in biology. Improving data flow analysis is in general, hard, but escape analysis, eg. by lexical scoping and argument passing, TS can prove local places of the use, and a For example, the issue you linked refers to the value of catching typos. While it's good for lax JS to acquire an overlay of assurance so that it don't happen, and had to be a popular ask, it's rare for a programming language to be driven by the goal of catching typos. Ideally their concepts are fewer, more versatile and rooted, and resiliency against typos just follows from the deeper aspects. To stay with the current issue at hand, it feels there's consensus about the utility of the issue ask and @AlCalzone's suggestion, as there's no objection other than, it's hard to implement. This is also but one example where common, proven coding patterns could be better supported by TS, and in the absence of such support, undesirable compromises are made, that reduce code quality, sometimes from many aspects eg. type safety, runtime, developer experience, and inclusivity toward new developers. When TS started, it had immediate use by the most sophisticated JS developers, lessened the need for property checks in unit tests: most users were expert in JS and stack. As now TS is very popular, it's good to instead think of it as a language, and from the viewpoint of new developers from a diverse background who learn TS as their first programming language. Where can one read up on TS stewardship discussions on what larger goals and values drive the evolution of TS, and what milestones are foreseen? Hard to make out a language just by ingesting a stream of our imperfect userland asks on gh. The issue ask was apparently not foreseen at the initial release of TS; it's concerning to see the length of time since asking for a widespread language property, followed by silence with no progress, plan or even problem acknowledgement linked to this issue, despite how heavily we developers rely on, and take for granted, referential transparency, eg. substitutability of an expression with its shorthand, when shaping our code. |
so will this be fixed? I tired to duplicate |
Now implemented in #44730. |
TypeScript Version: 2.0.3
Code
Expected behavior:
s
’s type can be narrowed indirectly via aconst
.Actual behavior:
s
’s type can only be narrowed via direct access.The text was updated successfully, but these errors were encountered: