Skip to content
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

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

Closed
falsandtru opened this issue Nov 2, 2019 · 8 comments
Closed

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

falsandtru opened this issue Nov 2, 2019 · 8 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@falsandtru
Copy link
Contributor

cc @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:

@falsandtru
Copy link
Contributor Author

Another case.

// b must be `ChildNode | 0` but actualy `ChildNode`
const b = document.querySelector('_')?.firstChild! ?? 0;

@AnyhowStep
Copy link
Contributor

AnyhowStep commented Nov 2, 2019

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

@fatcerberus
Copy link

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.

@RyanCavanaugh RyanCavanaugh added the Working as Intended The behavior described is the intended behavior; this is not a bug label Nov 4, 2019
@RyanCavanaugh
Copy link
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

@falsandtru
Copy link
Contributor Author

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.

@nmain
Copy link

nmain commented Nov 5, 2019

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.

@RyanCavanaugh
Copy link
Member

@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

@falsandtru
Copy link
Contributor Author

@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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

5 participants