You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We currently ban non-nullable assertions (!) completely with the ESLint rule @typescript-eslint/no-non-null-assertion.
However, there are arguments for using ! assertions as a tool for improving type safety.
Explanation
The ESLint rule @typescript-eslint/non-nullable-type-assertion-style provides alerts when a as assertion on a nullable type could be replaced with a ! instead.
Enabling this rule wouldn't require disabling @typescript-eslint/no-non-null-assertion. We could still mandate ESLint disable comments when using ! to make it clear that they should be used with caution and as an exception rather than the norm.
as enforces a positive definition that specifies what a type is, while ! applies a negative definition, specifying what a type isn't.
In other words, as prevents any type other than the asserted one from being applied, even if a more accurate one could be inferred due to code changes. ! doesn't share this brittleness, as it allows any other type to be inferred in place of the existing one, only stepping in to strip | undefined, | null from the type.
For this reason, replacing as with ! where applicable may represent a net improvement for type safety.
const example: string[] | undefined = ...
const bad = (example as string[]).pop();
const good = example!.pop();
2. TypeScript inference on nullability is limited
Some examples where the code guarantees the non-nullability of a variable, but TypeScript fails to infer this fact.
Optional chaining
while(queue[0]?.origin===originOfCurrentBatch){// `queue` and its head element are definedconstnextEntry=queue.shift()!;}while(queue.length>0){// `queue` and its head element are definedconstnextEntry=queue.shift()!;}
Array index access
if(chainIds.length>NETWORK_CACHE_LIMIT.MAX){constoldestChainId=chainIds.sort((c1,c2)=>Number(this.state.chainStatus[c2]?.lastVisited)-Number(this.state.chainStatus[c1]?.lastVisited),)[NETWORK_CACHE_LIMIT.MAX];// `oldestChainId` will always be defined, as `chainIds` is guaranteed to have at least `NETWORK_CACHE_LIMIT.MAX` elementsoldChainIds.push(oldestChainId!);}
Index signature
constoldChainIds=Object.keys(chainIds).filter((chainId)=>// `chainId` is of type `keyof typeof chainIds`, meaning `chainIds[chainId]` must be definedchainIds[chainId]!.lastVisited<currentTimestamp-NETWORK_CACHE_DURATION,);
Assertions made in a different conditional branch
/* * @param options.currentVersion - The current version. Required if * `isReleaseCandidate` is set, but optional otherwise. */exportasyncfunctionupdateChangelog({
currentVersion,
isReleaseCandidate,
tagPrefixes =['v'],}: {currentVersion?: string;isReleaseCandidate: boolean;tagPrefixes: [string,string[]];}){if(isReleaseCandidate&&!currentVersion){thrownewError(`A version must be specified if 'isReleaseCandidate' is set.`,);}// Due to the first null check, if `isReleaseCandidate` is truthy, `currentVersion` should always be truthyif(isReleaseCandidate&&awaitgetMostRecentTag({ tagPrefixes })===`${tagPrefixes[0]}${currentVersion!}`// `currentVersion` is inferred as 'string | undefined'){thrownewError(`Current version already has tag, which is unexpected for a release candidate.`,);}
...
The text was updated successfully, but these errors were encountered:
Motivation
We currently ban non-nullable assertions (
!
) completely with the ESLint rule@typescript-eslint/no-non-null-assertion
.However, there are arguments for using
!
assertions as a tool for improving type safety.Explanation
The ESLint rule
@typescript-eslint/non-nullable-type-assertion-style
provides alerts when aas
assertion on a nullable type could be replaced with a!
instead.Enabling this rule wouldn't require disabling
@typescript-eslint/no-non-null-assertion
. We could still mandate ESLint disable comments when using!
to make it clear that they should be used with caution and as an exception rather than the norm.In defense of
!
1.
!
is safer thanas
as
enforces a positive definition that specifies what a type is, while!
applies a negative definition, specifying what a type isn't.In other words,
as
prevents any type other than the asserted one from being applied, even if a more accurate one could be inferred due to code changes.!
doesn't share this brittleness, as it allows any other type to be inferred in place of the existing one, only stepping in to strip| undefined
,| null
from the type.For this reason, replacing
as
with!
where applicable may represent a net improvement for type safety.2. TypeScript inference on nullability is limited
Some examples where the code guarantees the non-nullability of a variable, but TypeScript fails to infer this fact.
The text was updated successfully, but these errors were encountered: