Repository navigation
Non-null assertion operator and the typeof operator #17370
Description
Activity
I think you're asking for #6606. For now, workarounds involve forcing the type checker to evaluate the type you care about while not causing much extra work at runtime:
class Foo {} class Bar<T extends Foo> {} declare const x : Foo | undefined if (false as true && (typeof x !== 'undefined')) { var definedX = x; // assignment never happens at runtime } const y = new Bar<typeof definedX>()
bradzacher commented
on Jul 24, 2017 ContributorAuthorMore actionsi mean, yeah #6606 would definitely solve this as it's a pretty all encompassing proposition...
It would be nice if there was a better error message to signify that the error is specifically that the expression isn't supported, rather than a 'semicolon expected' error.
KiaraGrouwstra commented
on Jul 24, 2017 ContributorMore actionsA potential alternative here would be for the compiler to expose
!on the type level. I'm not yet aware of outstanding proposals for that though.Reacted by Joseph Luck@tycho01 back to the #6606 discussion, is it going to be too many type-level operators, isn't? that was one of my points, we'll never get same expressiveness.
KiaraGrouwstra commented
on Jul 24, 2017 ContributorMore actionsI'd be interested to get their take on it. Evidently they didn't feel the expression level had too many operators to add that
!.
Personally my ideal situation would be to keep the two completely on-par. But yeah, the TS team may well be considerably more conservative.Edit: to get to your point, yeah, if we are to be stuck with a type level not on par with the expression level, that admittedly goes to validate the added value of your expression-first #6606 variant.
- addedIn DiscussionNot yet reached consensusNot yet reached consensusSuggestionAn idea for TypeScriptAn idea for TypeScript
on Jul 24, 2017 RyanCavanaugh commented
on Jul 24, 2017 MemberMore actionsWe can expand the grammar here bit by bit without going full-blast with #6606. This incremental change seems pretty reasonable
Reacted by kiaraReacted by Igor Oleinikovbradzacher commented
on Jul 24, 2017 ContributorAuthorMore actionsit would be great as (right now) there's no other way to scrub
null/undefinedat the expression level; making it more difficult to work with thestrictNullChecksoption at times.Ryan Cavanaugh (@RyanCavanaugh) Hm, I'd prefer full-blast (you might have already got this 😄) as it would cover much more cases at once.
KiaraGrouwstra commented
on Jul 25, 2017 ContributorMore actionsBrad Zacher (@bradzacher): I think you meant type level. :)
KiaraGrouwstra commented
on Jul 25, 2017 ContributorMore actionsRyan Cavanaugh (@RyanCavanaugh): on #6606, does the reluctance stem from perceived complexity of the implementation as you proposed it (link)? Because afaik, the proposal would not necessarily* bring breaking changes.
*: ignoring the keyword priority discussion raised by Igorbek for the expression-based proposal.
RyanCavanaugh commented
on Jul 25, 2017 MemberMore actions#6606 is accepting PRs and anyone can jump in, but we're not ready to commit team resources to it yet. The prioritization is based on a cost/benefit analysis: adding
!to the grammar here is probably a ~1/2-day work item (for someone on the team) but that other proposal is probably a 5-day or more work item (due to likely unknown design aspects that would only become apparent during implementation) plus a lot of ongoing complexity maintenance cost.Reacted by kiaraRyan Cavanaugh (@RyanCavanaugh) is #6606 accepting PRs even in expression-based syntax?
KiaraGrouwstra commented
on Jul 25, 2017 ContributorMore actionsOn-topic, with 6606 a type-level
!alternative could look like this:class Foo {} // expression level function application today, to test: declare function assert<T>(v: T | null | undefined): T; let a: Foo | undefined; let b = assert(a); // Foo // v type level function 'application' with #6606: type Assert<T> = (<U>(v: U | null | undefined) => U)(T); let x: Assert<Foo | undefined>; // Foo
bradzacher commented
on Jul 25, 2017 ContributorAuthorMore actionsfrom the looks of it - typescript doesn't let you have self invoking functions like that within a
typedeclaration.[ts] ';' expected. [ts] Cannot find name 'T'.KiaraGrouwstra commented
on Jul 26, 2017 ContributorMore actionsBrad Zacher (@bradzacher): yeah, the function 'application' there is not possible yet. Either flavor of the 6606 proposal could enable something similar to that.
Reacted by Brad ZacherKiaraGrouwstra commented
on Jul 26, 2017 ContributorMore actionsRyan Cavanaugh (@RyanCavanaugh) is #6606 accepting PRs even in expression-based syntax?
since we're just about down to aesthetics... welcome to
typeof fn(1 as any as MyType)!KiaraGrouwstra commented
on Aug 12, 2017 ContributorMore actionsKiaraGrouwstra commented
on Aug 21, 2017 ContributorMore actionsI made some initial progress at #17948, but still broken.
@tycho01 back to the #6606 discussion, is it going to be too many type-level operators, isn't? that was one of my points, we'll never get same expressiveness.
Seems they reconsidered in favor of your conclusion:
We have discussed this in a few design meetings now, and do not feel that adding a new type operator is the right way to go.
Type operators come with a maintainability cost, as well as learning cost by adding a new concept to the language.
An alternative here is to always remove null|undefined in type positions. this allows the use case in #14366 to follow as expected.Working example at 4d14c9f.
This should be doable today with
NonNullabletype.Reacted by kiarabradzacher commented
on Mar 4, 2018 ContributorAuthorMore actionsMohamed Hegazy (@mhegazy) it should be yeah! 👍
I would have liked the operator for it for consistency with non-type def syntax, but I understand and agree with the design decisions.
I see it was merged a few weeks ago. I'd assume that'll be part of the next minor version (2.8??).
do you know when that is being released?do you know when that is being released?
Reacted by Brad ZacherClosing as fixed by
NonNullabletype.Reacted by Brad Zacher and kiara- addedFixedA PR has been merged for this issueA PR has been merged for this issueand removedIn DiscussionNot yet reached consensusNot yet reached consensus
on Mar 9, 2018 - locked and limited conversation to collaborators
on Jul 25, 2018
TypeScript Version: 2.4.1
Code
Expected behavior:
the
t1statement should create atypeof typestring.the
t2statement should create atypeof typestring.Actual behavior:
the
t1statement errors with';' semicolon expected.the
t2statement creates atypeof typestring.There appears to be no way to achieve this without defining a separate variable, or by type guarding to remove the
undefined/null.With strict null checks on, this is especially troublesome in the case of generics with extends clauses, i.e.
It would be great if the non-null assertion operator worked natively in typeof statements, or even if you could use brackets to resolve the assertion before the typeof.