β¬ οΈ Back to Table of Contents
π non-nullable-type-assertion-style¶
π Analysis Summary¶
| Metric | Count |
|---|---|
| π§ Functions | 5 |
| π¦ Imports | 6 |
π Table of Contents¶
π οΈ File Location:¶
π packages/eslint-plugin/src/rules/non-nullable-type-assertion-style.ts
π€ Default Export¶
| Property | Value |
|---|---|
name |
'non-nullable-type-assertion-style' |
meta.type |
'suggestion' |
meta.docs.description |
'Enforce non-null assertions over explicit type assertions' |
meta.docs.recommended |
'stylistic' |
meta.docs.requiresTypeChecking |
true |
meta.fixable |
'code' |
meta.messages.preferNonNullAssertion |
'Use a ! assertion to more succinctly remove null and undefined from the type.' |
meta.schema |
[] |
defaultOptions |
[] |
Entry point: create β documented under Functions.
π¦ Imports¶
| Name | Source |
|---|---|
TSESTree |
@typescript-eslint/utils |
AST_NODE_TYPES |
@typescript-eslint/utils |
createRule |
../util |
getOperatorPrecedence |
../util |
getParserServices |
../util |
OperatorPrecedence |
../util |
Functions¶
create(context: any): { 'TSAsExpression, TSTypeAssertion'(node: TSESTree.TSAsExpr⦶
Parameters:
contextany
Returns: { 'TSAsExpression, TSTypeAssertion'(node: TSESTree.TSAsExpression | TSESTree.TSTypeAssertion): void; }
Calls:
getParserServices (from ../util)services.getTypeAtLocationtsutils.isTypeFlagSettsutils.unionConstituentstype.getConstraintcouldBeNullishtsutils.isUnionTypeoriginalTypes.filternonNullishOriginalTypes.includesassertedTypes.includesisConstAssertiongetTypesIfNotLoosesameTypeWithoutNullishcontext.sourceCode.getTextgetOperatorPrecedence (from ../util)services.esTreeNodeToTSNodeMap.getcontext.reportfixer.replaceText
Code
create(context) {
const services = getParserServices(context);
const getTypesIfNotLoose = (node: TSESTree.Node): ts.Type[] | undefined => {
const type = services.getTypeAtLocation(node);
if (
tsutils.isTypeFlagSet(type, ts.TypeFlags.Any | ts.TypeFlags.Unknown)
) {
return undefined;
}
return tsutils.unionConstituents(type);
};
const couldBeNullish = (type: ts.Type): boolean => {
if (tsutils.isTypeFlagSet(type, ts.TypeFlags.TypeParameter)) {
const constraint = type.getConstraint();
return constraint == null || couldBeNullish(constraint);
}
if (tsutils.isUnionType(type)) {
for (const part of type.types) {
if (couldBeNullish(part)) {
return true;
}
}
return false;
}
return tsutils.isTypeFlagSet(
type,
ts.TypeFlags.Null | ts.TypeFlags.Undefined,
);
};
const sameTypeWithoutNullish = (
assertedTypes: ts.Type[],
originalTypes: ts.Type[],
): boolean => {
const nonNullishOriginalTypes = originalTypes.filter(
type =>
!tsutils.isTypeFlagSet(
type,
ts.TypeFlags.Null | ts.TypeFlags.Undefined,
),
);
if (nonNullishOriginalTypes.length === originalTypes.length) {
return false;
}
for (const assertedType of assertedTypes) {
if (
couldBeNullish(assertedType) ||
!nonNullishOriginalTypes.includes(assertedType)
) {
return false;
}
}
for (const originalType of nonNullishOriginalTypes) {
if (!assertedTypes.includes(originalType)) {
return false;
}
}
return true;
};
const isConstAssertion = (
node: TSESTree.TSAsExpression | TSESTree.TSTypeAssertion,
): boolean => {
return (
node.typeAnnotation.type === AST_NODE_TYPES.TSTypeReference &&
node.typeAnnotation.typeName.type === AST_NODE_TYPES.Identifier &&
node.typeAnnotation.typeName.name === 'const'
);
};
return {
'TSAsExpression, TSTypeAssertion'(
node: TSESTree.TSAsExpression | TSESTree.TSTypeAssertion,
): void {
if (isConstAssertion(node)) {
return;
}
const originalTypes = getTypesIfNotLoose(node.expression);
if (!originalTypes) {
return;
}
const assertedTypes = getTypesIfNotLoose(node.typeAnnotation);
if (!assertedTypes) {
return;
}
if (sameTypeWithoutNullish(assertedTypes, originalTypes)) {
const expressionSourceCode = context.sourceCode.getText(
node.expression,
);
const higherPrecedenceThanUnary =
getOperatorPrecedence(
services.esTreeNodeToTSNodeMap.get(node.expression).kind,
ts.SyntaxKind.Unknown,
) > OperatorPrecedence.Unary;
context.report({
node,
messageId: 'preferNonNullAssertion',
fix(fixer) {
return fixer.replaceText(
node,
higherPrecedenceThanUnary
? `${expressionSourceCode}!`
: `(${expressionSourceCode})!`,
);
},
});
}
},
};
}
Internal helpers¶
Declared inside another function in this file.
getTypesIfNotLoose(node: TSESTree.Node): ts.Type[] | undefined¶
Parameters:
nodeTSESTree.Node
Returns: ts.Type[] | undefined
Calls:
services.getTypeAtLocationtsutils.isTypeFlagSettsutils.unionConstituents
Code
couldBeNullish(type: ts.Type): boolean¶
Parameters:
typets.Type
Returns: boolean
Calls:
tsutils.isTypeFlagSettype.getConstraintcouldBeNullishtsutils.isUnionType
Code
(type: ts.Type): boolean => {
if (tsutils.isTypeFlagSet(type, ts.TypeFlags.TypeParameter)) {
const constraint = type.getConstraint();
return constraint == null || couldBeNullish(constraint);
}
if (tsutils.isUnionType(type)) {
for (const part of type.types) {
if (couldBeNullish(part)) {
return true;
}
}
return false;
}
return tsutils.isTypeFlagSet(
type,
ts.TypeFlags.Null | ts.TypeFlags.Undefined,
);
}
sameTypeWithoutNullish(assertedTypes: ts.Type[], originalTypes: ts.Type[]): boolean¶
Parameters:
assertedTypests.Type[]originalTypests.Type[]
Returns: boolean
Calls:
originalTypes.filtertsutils.isTypeFlagSetcouldBeNullishnonNullishOriginalTypes.includesassertedTypes.includes
Code
(
assertedTypes: ts.Type[],
originalTypes: ts.Type[],
): boolean => {
const nonNullishOriginalTypes = originalTypes.filter(
type =>
!tsutils.isTypeFlagSet(
type,
ts.TypeFlags.Null | ts.TypeFlags.Undefined,
),
);
if (nonNullishOriginalTypes.length === originalTypes.length) {
return false;
}
for (const assertedType of assertedTypes) {
if (
couldBeNullish(assertedType) ||
!nonNullishOriginalTypes.includes(assertedType)
) {
return false;
}
}
for (const originalType of nonNullishOriginalTypes) {
if (!assertedTypes.includes(originalType)) {
return false;
}
}
return true;
}
isConstAssertion(node: TSESTree.TSAsExpression | TSESTree.TSTyβ¦): boolean¶
Parameters:
nodeTSESTree.TSAsExpression | TSESTree.TSTypeAssertion
Returns: boolean
Code
Generated by Syntax Scribe