β¬ οΈ Back to Table of Contents
π consistent-type-definitions¶
π Analysis Summary¶
| Metric | Count |
|---|---|
| π§ Functions | 2 |
| π¦ Imports | 6 |
π Table of Contents¶
π οΈ File Location:¶
π packages/eslint-plugin/src/rules/consistent-type-definitions.ts
π€ Default Export¶
| Property | Value |
|---|---|
name |
'consistent-type-definitions' |
meta.type |
'suggestion' |
meta.docs.description |
'Enforce type definitions to consistently use either interface or type' |
meta.docs.recommended |
'stylistic' |
meta.fixable |
'code' |
meta.messages.interfaceOverType |
'Use an interface instead of a type.' |
meta.messages.typeOverInterface |
'Use a type instead of an interface.' |
meta.schema |
[ { type: 'string', description: 'Which type definition syntax to prefer.', enum: ['interface', 'type'], }, ] |
defaultOptions |
['interface'] |
Entry point: create β documented under Functions.
π¦ Imports¶
| Name | Source |
|---|---|
TSESLint |
@typescript-eslint/utils |
TSESTree |
@typescript-eslint/utils |
AST_NODE_TYPES |
@typescript-eslint/utils |
createRule |
../util |
nullThrows |
../util |
NullThrowsReasons |
../util |
Functions¶
create(context: any, [option]: any): { TSInterfaceDeclaration(node: any): void; "TSTypeAliasDecl⦶
Parameters:
contextany[option]any
Returns: { TSInterfaceDeclaration(node: any): void; "TSTypeAliasDeclaration[typeAnnotation.type='TSTypeLiteral']"(node: TSESTree.TSTypeAliasDeclaration): void; }
Calls:
context.sourceCode .getAncestors(node) .somecontext.reportnullThrows (from ../util)context.sourceCode.getTokenBeforeNullThrowsReasons.MissingTokenfixer.replaceTextfixer.replaceTextRangefixer.removeRangeisCurrentlyTraversedNodeWithinModuleDeclarationfixes.pushnode.extends.forEachcontext.sourceCode.getTextfixer.insertTextAfter
Internal Comments:
/**
* Iterates from the highest parent to the currently traversed node
* to determine whether any node in tree is globally declared module declaration
*/
// replace 'type' with 'interface'. (x3)
// delete from the = to the { of the type, and put a space to be pretty. (x3)
// remove from the closing } through the end of the statement. (x3)
/**
* remove automatically fix when the interface is within a declare global
* @see {@link https://github.com/typescript-eslint/typescript-eslint/issues/2707}
*/ (x2)
Code
create(context, [option]) {
/**
* Iterates from the highest parent to the currently traversed node
* to determine whether any node in tree is globally declared module declaration
*/
function isCurrentlyTraversedNodeWithinModuleDeclaration(
node: TSESTree.Node,
): boolean {
return context.sourceCode
.getAncestors(node)
.some(
node =>
node.type === AST_NODE_TYPES.TSModuleDeclaration &&
node.declare &&
node.kind === 'global',
);
}
return {
...(option === 'interface' && {
"TSTypeAliasDeclaration[typeAnnotation.type='TSTypeLiteral']"(
node: TSESTree.TSTypeAliasDeclaration,
): void {
context.report({
node: node.id,
messageId: 'interfaceOverType',
fix(fixer) {
const typeToken = nullThrows(
context.sourceCode.getTokenBefore(
node.id,
token => token.value === 'type',
),
NullThrowsReasons.MissingToken('type keyword', 'type alias'),
);
const equalsToken = nullThrows(
context.sourceCode.getTokenBefore(
node.typeAnnotation,
token => token.value === '=',
),
NullThrowsReasons.MissingToken('=', 'type alias'),
);
const beforeEqualsToken = nullThrows(
context.sourceCode.getTokenBefore(equalsToken, {
includeComments: true,
}),
NullThrowsReasons.MissingToken('before =', 'type alias'),
);
return [
// replace 'type' with 'interface'.
fixer.replaceText(typeToken, 'interface'),
// delete from the = to the { of the type, and put a space to be pretty.
fixer.replaceTextRange(
[beforeEqualsToken.range[1], node.typeAnnotation.range[0]],
' ',
),
// remove from the closing } through the end of the statement.
fixer.removeRange([
node.typeAnnotation.range[1],
node.range[1],
]),
];
},
});
},
}),
...(option === 'type' && {
TSInterfaceDeclaration(node): void {
const fix = isCurrentlyTraversedNodeWithinModuleDeclaration(node)
? null
: (fixer: TSESLint.RuleFixer): TSESLint.RuleFix[] => {
const typeNode = node.typeParameters ?? node.id;
const fixes: TSESLint.RuleFix[] = [];
const firstToken = context.sourceCode.getTokenBefore(node.id);
if (firstToken) {
fixes.push(fixer.replaceText(firstToken, 'type'));
fixes.push(
fixer.replaceTextRange(
[typeNode.range[1], node.body.range[0]],
' = ',
),
);
}
node.extends.forEach(heritage => {
const typeIdentifier = context.sourceCode.getText(heritage);
fixes.push(
fixer.insertTextAfter(node.body, ` & ${typeIdentifier}`),
);
});
if (
node.parent.type === AST_NODE_TYPES.ExportDefaultDeclaration
) {
fixes.push(
fixer.removeRange([node.parent.range[0], node.range[0]]),
fixer.insertTextAfter(
node.body,
`\nexport default ${node.id.name}`,
),
);
}
return fixes;
};
context.report({
node: node.id,
messageId: 'typeOverInterface',
/**
* remove automatically fix when the interface is within a declare global
* @see {@link https://github.com/typescript-eslint/typescript-eslint/issues/2707}
*/
fix,
});
},
}),
};
}
Internal helpers¶
Declared inside another function in this file.
isCurrentlyTraversedNodeWithinModuleDeclaration(node: TSESTree.Node): boolean¶
Iterates from the highest parent to the currently traversed node to determine whether any node in tree is globally declared module declaration
Raw JSDoc
Calls:
context.sourceCode .getAncestors(node) .some
Code
Generated by Syntax Scribe