Skip to content

Non-null type assertions shouldn't affect optional chaining #34875

Description

@falsandtru

cc Anders Hejlsberg (@ahejlsberg)

TypeScript Version: 3.7.x-dev.20191101

Search Terms:

Code

const a = document.querySelector('_')?.textContent!;

Expected behavior:

Type of a is string | undefined.

Actual behavior:

Type of a is string.

This means document.querySelector('_').textContent! is valid and these are the equivalent to document.querySelector('_')!.textContent!.

Playground Link: http://www.typescriptlang.org/play/?ts=3.8.0-dev.20191101&ssl=1&ssc=53&pln=2&pc=23#code/MYewdgzgLgBAhjAvDAJiYBXAtgUzFAOgEcMcAnATwGUcAbHYKEMgCgHIB9NgSgH4CoOAB5QAwuEH4AhAG4gA

Related Issues:

Activity

  1. falsandtru commented on Nov 2, 2019

    @falsandtru
    ContributorAuthor

    Another case.

    // b must be `ChildNode | 0` but actualy `ChildNode`
    const b = document.querySelector('_')?.firstChild! ?? 0;
  2. AnyhowStep commented on Nov 2, 2019

    @AnyhowStep
    Contributor

    image

    Btw,

    A new ! post-fix expression operator may be used to assert that its operand is non-null and non-undefined in contexts where the type checker is unable to conclude that fact. Specifically, the operation x! produces a value of the type of x with null and undefined excluded.

    https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-0.html#non-null-assertion-operator

  3. fatcerberus commented on Nov 2, 2019

    @fatcerberus

    Memes aside, if the goal here is simply to remove the null possibility for textContent only, that's probably going to be difficult in general because ! applies to the entire expression and the compiler can't distinguish between T | undefined | undefined and T | undefined. By the time the compiler sees the !, the two levels of null possibility have already collapsed down to one.

  4. RyanCavanaugh commented on Nov 4, 2019

    @RyanCavanaugh
    Member

    This is the same as if you had written

    const _a = document.querySelector('_')?.textContent;
    const a = _a!;

    IOW ! applies to the entire operand expression, not just the property access

  5. falsandtru commented on Nov 4, 2019

    @falsandtru
    ContributorAuthor

    Can't you notice the problem that there is no way to infer the actual type string | null from document.querySelector('_')?.textContent even when using !? ! became useless with many cases using optional chaining.

  6. nmain commented on Nov 5, 2019

    @nmain

    Optional chaining covers common use cases with terse expressions. If you really need to go deep detail about each part of your expression; if it's important for your use case to distinguish when querySelector returns undefined vs when textContent returns null; then just break it out into separate statements and test each one.

  7. RyanCavanaugh commented on Nov 5, 2019

    @RyanCavanaugh
    Member

    falsandtru (@falsandtru) you'll have to get a time machine and take it up with TC39 in 2017, I guess. ?. won't propagate a null value and TS represents that

  8. falsandtru commented on Nov 5, 2019

    @falsandtru
    ContributorAuthor

    Ryan Cavanaugh (@RyanCavanaugh) Then I just replace null with undefined. Anyway the essential problem is the same. When developers introduce optional chaining, currently TypeScript forces developers to explicitly write the expected type in some cases like document.querySelector('_')?.textContent as string | undefined.

    The question is TypeScript won't resolve the new problem that optional chaining sometimes makes type inference to be impossible to infer the actual type?

  9. locked as resolved and limited conversation to collaborators on Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Working as IntendedThe behavior described is the intended behavior; this is not a bug

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions