To ensure robust TypeScript projects, you must configure ESLint with the
@typescript-eslint parser and enable strict type checking via the
strict flag in your
tsconfig.json. Even when using
//@ts-nocheck to bypass errors, proper linting rules can still catch structural issues, while the compiler validates types at build time. This dual approach prevents runtime failures and enforces consistent coding standards across your codebase.
Configuring the Linting Environment
The foundation of a reliable TypeScript project is a correctly configured ESLint setup. By default, standard ESLint rules do not understand TypeScript syntax, which leads to false positives or ignored errors. You need to install the specific parser and plugins that bridge this gap. The most common ecosystem uses
eslint,
@typescript-eslint/parser, and
@typescript-eslint/eslint-plugin.
Create an
.eslintrc.js or
.eslintrc.json file in your project root. Inside this configuration, you must extend the recommended presets provided by the TypeScript ESLint team. These presets include rules for variable declaration, no-unused-expressions, and other best practices tailored for static typing.
module.exports = {
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended'
],
rules: {
// Custom rules go here
}
};
When you run
npx eslint ., the tool will parse your
.ts files using the TypeScript AST (Abstract Syntax Tree). This allows it to identify syntax errors that are valid JavaScript but invalid TypeScript, such as using
any excessively or missing return types. If you have files marked with
//@ts-nocheck, the linter may still flag style violations because linting operates independently of the type checker's suppression directives.
Enabling Strict Type Checking
While linting handles style and basic syntax, TypeScript’s compiler ensures type safety. The key to catching early errors is enabling the
strict mode in your
tsconfig.json. This single flag activates a suite of checks that prevent many common bugs.
{
"compilerOptions": {
"strict": true,
"target": "ES6",
"module": "commonjs"
},
"include": ["src/**/*.ts"]
}
The
strict flag enables several sub-options:
- strictNullChecks: Variables cannot be undefined or null unless explicitly typed.
- strictFunctionTypes: Ensures function parameter contravariance and return type covariance.
- noImplicitAny: Raises an error if the compiler cannot infer a type, forcing explicit declarations.
If you are migrating an existing project, turning on
strict might reveal hundreds of errors. It is often better to enable these settings incrementally. However, for new projects, always start with
strict: true. This forces developers to write defensive code, reducing the likelihood of
TypeError: Cannot read properties of undefined errors at runtime.
Handling Suppressed Errors
Developers sometimes use
//@ts-nocheck or
// @ts-ignore to silence errors during rapid prototyping or when dealing with external libraries lacking type definitions. While convenient, these comments disable type checking for entire files or specific lines.
Linting tools like ESLint can detect these suppressions if configured correctly. You can add a rule to warn whenever
@ts-nocheck is used, encouraging developers to fix the underlying issue rather than hiding it. For example, you can enforce a rule that requires a comment explaining why the check was disabled.
rules: {
'@typescript-eslint/ban-ts-comment': [
'error',
{
'ts-nocheck': 'warn',
'ts-ignore': 'warn'
}
]
}
This strategy ensures that suppressed errors are reviewed during pull requests. If you rely heavily on third-party libraries, consider creating custom type declaration files (
*.d.ts) instead of ignoring errors. This keeps your codebase type-safe without relying on hacks. For more details on handling complex type assignments, see
Making TypeScript Recognize Object Assignment as Valid.
Integrating with Build Pipelines
To maintain quality, linting and type checking should be part of your continuous integration (CI) pipeline. Use scripts in your
package.json to automate these checks.
"scripts": {
"lint": "eslint src/**/*.{ts,tsx}",
"type-check": "tsc --noEmit",
"build": "npm run lint && npm run type-check && tsc"
}
Running
npm run build ensures that no code is deployed unless it passes both style and type checks. This prevents regressions where a developer introduces a typo or a type mismatch that breaks production. If you encounter issues with source maps or unclear error messages in your main entry point, refer to
Error Displayed in main.js Without Source File Reference for troubleshooting steps.
Frequently Asked Questions
Can I use ts-nocheck with ESLint enabled?
Yes, ESLint can run even if TypeScript ignores certain checks. However, ESLint does not automatically respect
ts-nocheck unless specifically configured to ignore TypeScript-specific warnings. You should configure ESLint to warn on these comments to encourage fixing them.
What is the difference between linting and type checking?
Linting checks code style, potential bugs, and readability using pattern matching. Type checking verifies that variables match their declared types and that operations are valid within the TypeScript type system. They serve complementary roles in code quality.
How do I handle legacy JavaScript files in a TypeScript project?
You can mark legacy files with
// @ts-nocheck to skip type checking. Alternatively, rename them to
.js and configure your
tsconfig.json to exclude them from compilation. Ensure your ESLint config includes appropriate parsers for mixed JS/TS projects.
Why does my CI fail even though the code runs locally?
This usually happens due to environment differences or outdated dependencies. Ensure your CI environment uses the same Node.js version and dependency versions as your local machine. Also, verify that
strict mode is enabled in the CI build script.
Is it safe to remove all ts-nocheck comments eventually?
Yes, removing them improves long-term maintainability. Replace them with proper type definitions or interface declarations. If a library lacks types, create a
types.d.ts file to define the expected shape, ensuring full type coverage.