Get Started
- CodeAnt AI
- Control Center
- Pull Request Review
- IDE
- Compliance
- Anti-Patterns
- Code Governance
- Infrastructure Security Database
- Application Security Database
Typescript
Require that function overload signatures be consecutive
interface ExampleInterface {
overloadMethod(foo: string): number;
someOtherMethod(): void;
overloadMethod(foo: number): number;
}
- Ensures readability and maintainability by grouping function overloads together, making it easier for developers to understand the variations of a function and how it can be used.
- Helps in preventing accidental duplication of function overloads by making it clear which overloads exist and discouraging the scattered definition of similar functionalities.
- Facilitates easier refactoring and extension of functionalities since related overloads are kept in one place, making it straightforward to modify or extend existing behaviors without missing any overload variant.
- Improves navigation within the codebase for developers, as finding all available overloads of a method becomes more straightforward when they are defined consecutively, thereby reducing the time needed to understand or update the code.
Require consistently using either T[]
or Array<T>
for arrays
const numbers: Array<number> = [1, 2, 3];
const words: Array<string> = ["hello", "world"];
- Ensures consistency in array type declarations within a TypeScript codebase, making the code more uniform and easier to understand, especially for teams or when following a specific coding standard or style guide.
- Helps in preventing the mix of
Array<T>
andT[]
styles in the code, which could potentially lead to confusion or errors, especially for developers new to TypeScript or those working across multiple projects with different style preferences. - Can improve readability and conciseness of the code, as using
T[]
is generally shorter and more to the point compared toArray<T>
, making the code less cluttered and quicker to read and understand. - Facilitates easier code maintenance and refactoring by enforcing a single array syntax style, reducing the cognitive load on developers to remember or decide which style to use when declaring array types, leading to faster development and fewer errors.
Disallow awaiting a value that is not a Thenable
async function processData() {
let data = getValue(); // Assume getValue() returns a non-Promise value.
let result = await data; // This is incorrect because 'data' is not a Promise.
console.log(result);
}
function getValue() {
return 42;
}
- Ensures consistency and predictability in asynchronous operations by enforcing the use of
await
only with actual Promise objects (Thenables), thus preventing runtime errors from awaiting non-Promise values. - Improves code readability and understanding by clearly marking operations that are asynchronous and depend on the resolution of Promises, making it easier for developers to identify asynchronous flows within their code.
- Helps in identifying and refactoring potential misuse of the
await
keyword with values that do not represent asynchronous operations, thereby guiding developers towards correct usage patterns and promoting best practices in asynchronous programming. - Assists in the prevention of subtle bugs that may occur when accidentally awaiting a value that is not a Promise, such as unintentionally blocking the execution thread or misinterpreting the value of the awaited expression, by providing early feedback during development.
Disallow @ts-<directive>
comments or require descriptions after directives
// @ts-ignore
let num: number = 'this is a string';
- Discourages the use of
@ts-<directive>
comments like@ts-ignore
without an accompanying explanation, promoting better code documentation and clarity on why type checking is being bypassed. - Helps in maintaining a cleaner codebase by ensuring that developers provide a valid reason when using TypeScript directive comments, which can assist future maintainers in understanding context.
- Reduces technical debt by encouraging developers to fix type issues directly instead of using directives as a workaround, leading to more robust and type-safe code.
- Aids in code review processes by providing context to reviewers on why certain TypeScript errors or warnings are being ignored, ensuring that these exceptions are justified and well-documented.
Disallow // tslint:<rule-flag>
comments
// This file contains examples of TypeScript code.
// tslint:disable-next-line:no-any
let data: any; // Disabling the rule for no-any type explicitly using a TSLint comment.
function processData(input: string) {
// tslint:disable no-console
console.log(input); // Disabling the rule for no-console explicitly using a TSLint comment.
}
processData('Hello, world!');
- Encourages the migration from TSLint to ESLint for TypeScript projects by specifically targeting and disallowing TSLint rule suppression comments, streamlining the code linting process under one tool.
- Enhances code maintainability and readability by ensuring that all linting instructions are consistently using ESLint syntax, making it easier for developers to understand and manage the rules applied across the codebase.
- Aids in the standardization of code quality tools within projects that have transitioned from TSLint to ESLint, eliminating the confusion of mixing commands from two different linters.
- Helps in fully utilizing the capabilities and updates provided by ESLint, especially those tailored for TypeScript through the
@typescript-eslint
plugin, by redirecting developers to use the appropriate ESLint rules instead of the now-deprecated TSLint comments.
Disallow certain types
function logValue(value: {}) {
console.log(value);
}
logValue("This could be anything, too broad!");
-
This ESLint rule prevents the usage of the
{}
type in TypeScript, which represents an empty object but actually allows any non-nullish value, leading to potential misuse where stricter type checking is expected. It encourages developers to explicitly state their intent, enhancing code readability and maintainability. -
By enforcing the use of more descriptive type annotations like
unknown
instead of{}
, it helps to catch type-related errors at compile time rather than runtime. This can lead to more robust and predictable code behavior, as developers are forced to narrow down the type before usage. -
The rule aids in the gradual improvement of codebases by highlighting areas where type definitions are too broad or potentially unsafe. It serves as an educational tool for teams, promoting best practices in type definition and contributing to a culture of quality and precision in development.
-
It ensures a consistent approach to typing across a project or organization, reducing the cognitive load on developers who work with the codebase. By standardizing the avoidance of the
{}
type in favor of more specific types likeunknown
, the rule helps in maintaining a high level of type safety.
Disallow or enforce spaces inside of blocks after opening block and before closing block
function example() {
if(true) {return false;}
}
- Ensures consistent spacing inside block braces, which improves readability by visually separating the block’s contents from its boundaries. This makes it easier for developers to identify the start and end of a block at a glance.
- Helps maintain a uniform coding style across the project, which is important for collaborative work. When everyone follows the same spacing rule, it reduces the probability of merge conflicts and makes peer review processes smoother.
- Decreases the likelihood of syntax errors in densely written blocks of code. Spaces inside blocks can make it less likely for developers to accidentally join symbols or keywords, which might lead to runtime errors or unintended behavior.
- By enforcing or disallowing spaces directly after opening and before closing blocks, it can also assist in catching some minification issues earlier. Unintended removal of spaces during the minification process might lead to code breaking changes, which this rule could help to mitigate by enforcing consistent block spacing.
Enforce consistent brace style for blocks
if (condition)
{
// Actions to perform if the condition is true
doSomething();
}
else
{
// Actions to perform if the condition is false
doSomethingElse();
}
- Enforces a consistent brace style across TypeScript codebases, which can significantly improve code readability and maintainability by ensuring that all block-level code follows the same structure.
- Helps prevent common syntax errors that may occur due to mismatched or misused braces, reducing the potential for runtime errors and the time spent on debugging.
- Makes it easier for developers, especially those new to the codebase, to quickly understand the structure and flow of the code by providing a predictable format for block declarations, such as
if-else
statements, loops, and function blocks. - Supports automated code formatting tools and linters in maintaining a uniform code style, thereby reducing the amount of manual corrections developers need to make during code reviews or pre-commit checks, ultimately improving team efficiency and collaboration.
Enforce that literals on classes are exposed in a consistent style
class Config {
// Directly expose a literal property
readonly maxUsers = 10;
}
- Ensures consistency in how class properties are exposed, whether directly as class fields or via getter methods, making the codebase more uniform and predictable for developers.
- Helps in enforcing a coding standard across the team, especially in projects using TypeScript, by dictating how literals should be defined within classes, which can improve readability and maintainability.
- Can aid in optimizing class property access performance, depending on the chosen style (direct access vs getter), by encouraging a deliberate choice between them based on the use case.
- Allows teams to prevent inadvertent modifications to class properties by guiding developers towards using getters for exposing read-only values, thereby enhancing the immutability of class instances.
Enforce that class methods utilize this
class Shape {
calculateArea(side) {
return side * side;
}
}
- Ensures class methods that do not use
this
are statically defined, which can lead to better organization of the code by clearly distinguishing between methods that operate on instance variables and those that don’t. - Promotes the use of static methods, which can improve performance by not necessitating the instantiation of a class to call such methods, potentially leading to more efficient code execution in scenarios where instance-related features are not required.
- Helps in identifying methods that could be potentially refactored into utility functions outside the class, thus encouraging a more functional programming approach where appropriate and reducing the class’s responsibility.
- Improves readability and maintainability of the code by providing an explicit indication of methods’ interaction (or lack thereof) with the class instance, making the developer’s intention clearer and aiding in future code modifications or extensions.
Require or disallow trailing commas
const obj = {
name: "John",
age: 30
}
function example(
param1,
param2
) {
// Function body...
}
const arr = [
1,
2
]
-
It enforces a consistent use of trailing commas in object literals, arrays, and function parameters, which helps in minimizing the diff when adding or removing items. This cleanliness in version control diffs makes it easier to track changes over time without extraneous line modifications.
-
The rule reduces the risk of syntax errors in multi-line constructs, as adding a new item to a list without remembering to add a comma to the previous item is a common mistake. Enforcing trailing commas means that each item addition or subtraction only affects a single line.
-
Applying this rule can streamline code reviews by eliminating discussions about stylistic preferences regarding trailing commas. When the rule is adopted, it ensures all team members adhere to the same coding standard, allowing reviewers to focus on more critical aspects of the code review process.
-
The rule flexibility allows teams to configure it according to their preferences, supporting both the enforcement of trailing commas where possible and their disallowance, catering to different coding styles and preferences within different projects or teams.
Enforce consistent spacing before and after commas
function example(a,b , c ,d) {
return [a,b , c ,d];
}
- It ensures a consistent appearance of comma-separated lists throughout the codebase, which enhances readability and maintains a uniform coding style. By enforcing spacing rules specifically before and after commas, the code becomes cleaner and more organized, making it easier to read and understand.
- This rule can help in reducing the occurrence of petty syntax errors or typos related to comma placement that might otherwise be overlooked. By standardizing the spacing around commas, it indirectly aids in catching potentially problematic code segments that could result in errors during compilation or runtime.
- It simplifies the process of code review by eliminating the need for manual checks on comma spacing conventions. Since the rule mandates a specific style for spacing around commas, reviewers can focus on more critical aspects of the code rather than stylistic preferences.
- Automated tools can fix spacing inconsistencies automatically based on this rule, which can significantly speed up the process of formatting code and ensuring it adheres to the project’s coding standards. This automatic correction capability can reduce the time developers spend on mundane formatting tasks, allowing them to concentrate on more complex and productive tasks.
Enforce specifying generic type arguments on type annotation or constructor name of a constructor call
class Box<T> {
constructor(public value: T) {}
}
// Bad: Type argument is not explicitly specified.
const box = new Box(123);
- Encourages explicit type definition, enhancing code readability and maintainability by clearly specifying what type is expected or required, rather than leaving it to be inferred. This makes the code easier to understand at a glance, especially in complex projects or when returning to the code after some time.
- Helps in catching type-related errors at compile time, rather than runtime. By enforcing generics to be specified, it allows TypeScript to validate types more strictly, leading to early detection of potential bugs that may arise from type mismatches.
- Promotes the use of TypeScript’s generics effectively, ensuring that developers leverage the full capabilities of TypeScript’s type system. This rule guides developers in employing a consistent approach to generic type usage, making the codebase more uniform and predictable.
- Facilitates better documentation and tooling support, as explicit types improve the accuracy of autocompletion, type checking, and API documentation generated tools. This can lead to a more efficient development process, as developers can rely on tooling to understand the codebase quickly.
Require or disallow the Record
type
interface BadExample {
[key: string]: number;
}
const scores: BadExample = {
alice: 10,
bob: 20,
};
- Enforces a consistent coding style when defining objects with a string index signature, improving code readability and maintainability.
- Helps in avoiding the more verbose interface or type aliases syntax for simple index signatures, thus making the codebase cleaner and more succinct.
- Promotes the usage of
Record
type which can lead to easier refactoring and stronger type checks, especially in larger codebases where explicit types are beneficial for understandability. - Prevents potential inconsistencies and errors in how indexed objects are defined and used across different parts of the application, ensuring a uniform approach to type definitions.
Enforce consistent usage of type assertions
// Assuming the rule is configured to prefer 'as Type' syntax
let someValue: any = "This is a string";
let strLength: number = (<string>someValue).length; // Using '<Type>' syntax
let anotherStrLength: number = (someValue as string).length; // Using 'as Type' syntax
- This ESLint rule helps maintain consistency across the codebase regarding the usage of type assertions in TypeScript, making the code easier to read and understand. For example, it enforces the use of either
as Type
or<Type>
syntax consistently, based on the configuration. - By enforcing a consistent type assertion syntax, it potentially reduces the cognitive load for developers who are reading or reviewing the code. When the syntax for type assertions is uniform throughout a project, it’s easier for developers to understand type conversions at a glance without needing to mentally parse different syntax styles.
- The rule can help prevent subtle bugs that might arise from misunderstandings or misuse of the two type assertion syntaxes (
as Type
vs.<Type>
), particularly for developers who might not be aware of the nuances or have a preference for one over the other. A consistent syntax ensures that type assertions are made explicitly and correctly throughout the application. - It encourages best practices in code styling specifically tailored for TypeScript projects. Since TypeScript is a superset of JavaScript that adds static types, using this rule helps exploit one of TypeScript’s main features (types) more effectively and securely by ensuring that type assertions, which are a key part of working with types, are used consistently.
Enforce type definitions to consistently use either interface
or type
type Product = {
id: number;
name: string;
price: number;
};
interface User {
id: number;
username: string;
}
-
Improves Code Consistency: Using this rule ensures that all type definitions within a codebase follow a consistent structure, whether it’s always using
interface
or always usingtype
. Consistency in coding style makes the code more readable and maintainable, especially for teams. -
Reduces Confusion: By enforcing a single method of defining types, it eliminates confusion for developers on when to use
interface
vstype
. In TypeScript, while both have their specific use cases, they are often interchangeable. Standardizing on one reduces cognitive load for the developers. -
Easier Refactoring: Should there ever be a need to refactor type definitions (for example, from
type
tointerface
to leverage interface merging), having a consistent starting point makes the process more straightforward and less error-prone. -
Encourages Best Practices: Depending on the chosen style (
interface
ortype
), the rule indirectly encourages best practices associated with that method. For example, ifinterface
is chosen, it promotes the use of interface merging. Conversely, iftype
is chosen, it might encourage leveraging union types more effectively.
Enforce consistent usage of type exports
// A TypeScript file that exports both a type and value together
export { MyType, myFunction } from './myModule';
interface MyType {
// Interface definition
}
const myFunction = () => {
// Some function implementation
}
-
It promotes clear separation between type and value exports, which enhances code readability and maintainability. This differentiation helps developers quickly identify what is being imported or exported at a glance, reducing cognitive load when navigating through code.
-
By enforcing the consistent usage of type exports, it helps ensure that TypeScript’s advanced type system is leveraged properly. This practice can prevent potential issues related to the TypeScript compilation process, such as unintentional inclusion of types in the JavaScript runtime, where they are not needed.
-
This rule aids in avoiding common errors that stem from mixed export statements. For instance, attempting to import a type as a value could lead to undefined behavior or runtime errors. Enforcing consistent type exports helps mitigate such errors by making the exports intention-clear.
-
It fosters better organization of code, making it easier for developers to refactor and reorganize without affecting the exported API surface. By clearly separating types and values, any changes made to the structure or location of types do not impact the value exports, thus minimizing the risk of introducing breaking changes inadvertently.
Enforce consistent usage of type imports
import { SomeInterface } from './some-module';
-
Enforces the use of
import type
for TypeScript types and interfaces, which makes the intention of importing such entities solely for type-checking purposes clear. This enhances code readability and understanding, especially for new developers or when revisiting the code after some time. -
Reduces the runtime footprint of the code by ensuring that only the necessary imports are included in the compiled JavaScript output. Since types are erased during TypeScript compilation, using
import type
prevents the JavaScript engine from trying to load modules that are only needed for type checking, optimizing performance. -
Helps maintain consistency across the codebase when importing types. By adhering to a specific rule for type imports, it avoids a mix of styles that can lead to confusion or the belief that different forms of import statements have different behaviors or implications.
-
Improves tooling support, as some tools and bundlers might leverage the explicit distinction between type imports and regular imports to optimize bundling and eliminate dead code more effectively. This rule can help in setting up a project environment that is more friendly to such optimizations, contributing to better build performance.
Enforce default parameters to be last
function greet(message = "Hi", name) {
return `${message} ${name}!`;
}
- Ensures clarity in function calls by positioning default parameters at the end, which helps in understanding which parameters are mandatory and which are optional at a glance, as seen in the shift from
function greet(message = "Hi", name) {...}
tofunction greet(name, message = "Hi") {...}
. - Reduces potential errors when calling functions without specifying all arguments, because in the corrected example (
function greet(name, message = "Hi") {...}
), it is easy to omit the second argument without affecting the function’s behavior, whereas in the problematic example, omitting the second argument (name
) would lead to errors or unexpected behavior. - Promotes consistency in function signatures across the codebase by enforcing a standard order of parameters, making code easier to read, understand, and maintain. This rule turns the focus to the default arguments by structuring them after required parameters.
- Enhances code refactoring and maintenance by making it less error-prone to add new parameters to functions in the future. Since default parameters are already positioned last as per this rule, adding new mandatory parameters doesn’t necessitate a reordering of parameters, as seen going from the ‘bad’ to ‘fix’ examples, which could potentially break calls to the function elsewhere in the codebase.
Enforce dot notation whenever possible
const person = {
name: 'John Doe',
age: 30
};
// Access using square bracket notation
const personName = person['name'];
const personAge = person['age'];
- Encourages consistency in codebase: Utilizing this ESLint rule will steer developers towards using dot notation consistently when accessing properties of an object, making the code more uniform and predictable.
- Improves readability: Dot notation is generally more readable than bracket notation, particularly when the property being accessed is a static name. This rule will make code easier to read and understand, especially for new developers or those reviewing the code.
- Potential for minor performance benefits: While the performance difference is usually negligible, dot notation can be slightly faster than bracket notation in some JavaScript engines because it does not require parsing a string to access the property. Enforcing this rule may lead to marginally more efficient code.
- Reduces the likelihood of typos: When using bracket notation with strings to access properties, it’s easier to make typos in the property name, which might not be immediately evident. Dot notation, being more direct, naturally reduces the chance of such errors, especially as it often benefits from IDE autocompletion features.
Require explicit return types on functions and class methods
// TypeScript code without explicit function return type
function calculateSum(a: number, b: number) {
return a + b;
}
class Calculator {
add(a: number, b: number) {
return a + b;
}
}
- Enforcing explicit return types on functions and class methods increases code readability and maintainability by clearly indicating to developers what type of value they should expect from a function call, reducing the chances of runtime errors due to type mismatches.
- This rule reduces the reliance on TypeScript’s type inference for function return types, which can be particularly beneficial in larger or more complex codebases where inferred types might be less obvious or predictable, ensuring that the developer’s intent is explicitly communicated and reducing potential for errors.
- By requiring explicit return types, it encourages developers to think more critically about the data their functions are processing and returning, potentially leading to better-designed functions and APIs as developers are forced to explicitly consider and document the data types they are working with.
- It enhances tooling support, such as IntelliSense in IDEs, by providing explicit type information, which can improve the developer experience through more accurate autocomplete suggestions and inline documentation, making it easier to understand and integrate with existing code.