📄 no-unnecessary-type-assertion.ts
¶
📊 Analysis Summary¶
Metric | Count |
---|---|
🔧 Functions | 7 |
📦 Imports | 15 |
📊 Variables & Constants | 7 |
📑 Type Aliases | 2 |
📚 Table of Contents¶
🛠️ File Location:¶
📂 packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts
📦 Imports¶
Name | Source |
---|---|
Scope |
@typescript-eslint/scope-manager |
TSESTree |
@typescript-eslint/utils |
ReportFixFunction |
@typescript-eslint/utils/ts-eslint |
AST_NODE_TYPES |
@typescript-eslint/utils |
AST_TOKEN_TYPES |
@typescript-eslint/utils |
createRule |
../util |
getConstrainedTypeAtLocation |
../util |
getContextualType |
../util |
getDeclaration |
../util |
getModifiers |
../util |
getParserServices |
../util |
isNullableType |
../util |
isTypeFlagSet |
../util |
nullThrows |
../util |
NullThrowsReasons |
../util |
Variables & Constants¶
Name | Type | Kind | Value | Exported |
---|---|---|---|---|
parentScope |
Scope | null |
let/var | declaratorScope |
✗ |
maybeDeclarationNode |
any |
const | parent.parent! |
✗ |
uncastPartsSet |
Set<unknown> |
const | new Set(uncastParts) |
✗ |
wouldSameTypeBeInferred |
boolean |
const | `castTypeIsLiteral | |
? isImplicitlyNarrowedLiteralDeclaration(node) | ||||
: !typeAnnotationIsConstAssertion` | ✗ | |||
isValidUndefined |
any |
const | `typeIncludesUndefined | |
? contextualTypeIncludesUndefined | ||||
: true` | ✗ | |||
isValidNull |
any |
const | `typeIncludesNull | |
? contextualTypeIncludesNull | ||||
: true` | ✗ | |||
isValidVoid |
any |
const | `typeIncludesVoid | |
? contextualTypeIncludesVoid | ||||
: true` | ✗ |
Functions¶
isPossiblyUsedBeforeAssigned(node: TSESTree.Expression): boolean
¶
Code
function isPossiblyUsedBeforeAssigned(node: TSESTree.Expression): boolean {
const declaration = getDeclaration(services, node);
if (!declaration) {
// don't know what the declaration is for some reason, so just assume the worst
return true;
}
if (
// non-strict mode doesn't care about used before assigned errors
tsutils.isStrictCompilerOptionEnabled(
compilerOptions,
'strictNullChecks',
) &&
// ignore class properties as they are compile time guarded
// also ignore function arguments as they can't be used before defined
ts.isVariableDeclaration(declaration)
) {
// For var declarations, we need to check whether the node
// is actually in a descendant of its declaration or not. If not,
// it may be used before defined.
// eg
// if (Math.random() < 0.5) {
// var x: number = 2;
// } else {
// x!.toFixed();
// }
if (
ts.isVariableDeclarationList(declaration.parent) &&
// var
declaration.parent.flags === ts.NodeFlags.None &&
// If they are not in the same file it will not exist.
// This situation must not occur using before defined.
services.tsNodeToESTreeNodeMap.has(declaration)
) {
const declaratorNode: TSESTree.VariableDeclaration =
services.tsNodeToESTreeNodeMap.get(declaration);
const scope = context.sourceCode.getScope(node);
const declaratorScope = context.sourceCode.getScope(declaratorNode);
let parentScope: Scope | null = declaratorScope;
while ((parentScope = parentScope.upper)) {
if (parentScope === scope) {
return true;
}
}
}
if (
// is it `const x!: number`
declaration.initializer == null &&
declaration.exclamationToken == null &&
declaration.type != null
) {
// check if the defined variable type has changed since assignment
const declarationType = checker.getTypeFromTypeNode(declaration.type);
const type = getConstrainedTypeAtLocation(services, node);
if (
declarationType === type &&
// `declare`s are never narrowed, so never skip them
!(
ts.isVariableDeclarationList(declaration.parent) &&
ts.isVariableStatement(declaration.parent.parent) &&
tsutils.includesModifier(
getModifiers(declaration.parent.parent),
ts.SyntaxKind.DeclareKeyword,
)
)
) {
// possibly used before assigned, so just skip it
// better to false negative and skip it, than false positive and fix to compile erroring code
//
// no better way to figure this out right now
// https://github.com/Microsoft/TypeScript/issues/31124
return true;
}
}
}
return false;
}
-
JSDoc:
-
Parameters:
node: TSESTree.Expression
- Return Type:
boolean
- Calls:
getDeclaration (from ../util)
tsutils.isStrictCompilerOptionEnabled
ts.isVariableDeclaration
ts.isVariableDeclarationList
services.tsNodeToESTreeNodeMap.has
services.tsNodeToESTreeNodeMap.get
context.sourceCode.getScope
checker.getTypeFromTypeNode
getConstrainedTypeAtLocation (from ../util)
ts.isVariableStatement
tsutils.includesModifier
getModifiers (from ../util)
- Internal Comments:
// don't know what the declaration is for some reason, so just assume the worst // non-strict mode doesn't care about used before assigned errors (x4) // ignore class properties as they are compile time guarded (x3) // also ignore function arguments as they can't be used before defined (x3) // For var declarations, we need to check whether the node // is actually in a descendant of its declaration or not. If not, // it may be used before defined. // eg // if (Math.random() < 0.5) { // var x: number = 2; // } else { // x!.toFixed(); // } // var (x4) // If they are not in the same file it will not exist. (x4) // This situation must not occur using before defined. (x4) // is it `const x!: number` (x5) // check if the defined variable type has changed since assignment (x2) // `declare`s are never narrowed, so never skip them // possibly used before assigned, so just skip it // better to false negative and skip it, than false positive and fix to compile erroring code // // no better way to figure this out right now // https://github.com/Microsoft/TypeScript/issues/31124
isConstAssertion(node: TSESTree.TypeNode): boolean
¶
Code
- Parameters:
node: TSESTree.TypeNode
- Return Type:
boolean
isTemplateLiteralWithExpressions(expression: TSESTree.Expression): boolean
¶
Code
- Parameters:
expression: TSESTree.Expression
- Return Type:
boolean
`isImplicitlyNarrowedLiteralDeclaration({¶
expression,
parent,
}: TSESTree.TSAsExpression | TSESTree.TSTypeAssertion): boolean`
Code
function isImplicitlyNarrowedLiteralDeclaration({
expression,
parent,
}: TSESTree.TSAsExpression | TSESTree.TSTypeAssertion): boolean {
/**
* Even on `const` variable declarations, template literals with expressions can sometimes be widened without a type assertion.
* @see https://github.com/typescript-eslint/typescript-eslint/issues/8737
*/
if (isTemplateLiteralWithExpressions(expression)) {
return false;
}
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const maybeDeclarationNode = parent.parent!;
return (
(maybeDeclarationNode.type === AST_NODE_TYPES.VariableDeclaration &&
maybeDeclarationNode.kind === 'const') ||
(parent.type === AST_NODE_TYPES.PropertyDefinition && parent.readonly)
);
}
- Parameters:
{ expression, parent, }: TSESTree.TSAsExpression | TSESTree.TSTypeAssertion
- Return Type:
boolean
- Calls:
isTemplateLiteralWithExpressions
- Internal Comments:
isTypeUnchanged(uncast: ts.Type, cast: ts.Type): boolean
¶
Code
function isTypeUnchanged(uncast: ts.Type, cast: ts.Type): boolean {
if (uncast === cast) {
return true;
}
if (
isTypeFlagSet(uncast, ts.TypeFlags.Undefined) &&
isTypeFlagSet(cast, ts.TypeFlags.Undefined) &&
tsutils.isCompilerOptionEnabled(
compilerOptions,
'exactOptionalPropertyTypes',
)
) {
const uncastParts = tsutils
.unionConstituents(uncast)
.filter(part => !isTypeFlagSet(part, ts.TypeFlags.Undefined));
const castParts = tsutils
.unionConstituents(cast)
.filter(part => !isTypeFlagSet(part, ts.TypeFlags.Undefined));
if (uncastParts.length !== castParts.length) {
return false;
}
const uncastPartsSet = new Set(uncastParts);
return castParts.every(part => uncastPartsSet.has(part));
}
return false;
}
- Parameters:
uncast: ts.Type
cast: ts.Type
- Return Type:
boolean
- Calls:
isTypeFlagSet (from ../util)
tsutils.isCompilerOptionEnabled
tsutils .unionConstituents(uncast) .filter
tsutils .unionConstituents(cast) .filter
castParts.every
uncastPartsSet.has
isTypeLiteral(type: ts.Type): any
¶
Code
- Parameters:
type: ts.Type
- Return Type:
any
- Calls:
type.isLiteral
tsutils.isBooleanLiteralType
removeExclamationFix(fixer: any): any
¶
Code
- Parameters:
fixer: any
- Return Type:
any
- Calls:
nullThrows (from ../util)
context.sourceCode.getLastToken
NullThrowsReasons.MissingToken
fixer.removeRange