Skip to content

chore: enable no-unsafe-assignment internally #3280

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ module.exports = {
],

// TODO - enable these new recommended rules
'@typescript-eslint/no-unsafe-assignment': 'off',
'@typescript-eslint/no-unsafe-member-access': 'off',
'@typescript-eslint/no-unsafe-return': 'off',
'@typescript-eslint/restrict-template-expressions': 'off',
Expand Down Expand Up @@ -168,6 +167,7 @@ module.exports = {
'jest/globals': true,
},
rules: {
'@typescript-eslint/no-unsafe-assignment': 'off',
'eslint-plugin/no-identical-tests': 'error',
'jest/no-disabled-tests': 'warn',
'jest/no-focused-tests': 'error',
Expand Down
3 changes: 2 additions & 1 deletion packages/eslint-plugin-internal/src/util/createRule.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { ESLintUtils } from '@typescript-eslint/experimental-utils';

// note - cannot migrate this to an import statement because it will make TSC copy the package.json to the dist folder
const version = require('../../package.json').version;
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const version: string = require('../../package.json');

const createRule = ESLintUtils.RuleCreator(
name =>
Expand Down
7 changes: 4 additions & 3 deletions packages/eslint-plugin-tslint/src/rules/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { Configuration, RuleSeverity } from 'tslint';
import { CustomLinter } from '../custom-linter';

// note - cannot migrate this to an import statement because it will make TSC copy the package.json to the dist folder
const version = require('../../package.json').version;
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const version: string = require('../../package.json');

const createRule = ESLintUtils.RuleCreator(
() =>
Expand Down Expand Up @@ -62,8 +63,8 @@ export default createRule<Options, MessageIds>({
docs: {
description:
'Wraps a TSLint configuration and lints the whole source using TSLint',
// one off special category for this plugin
category: 'TSLint' as any, // eslint-disable-line @typescript-eslint/no-explicit-any
// @ts-expect-error - We know this is a one off special category for this plugin
category: 'TSLint',
recommended: false,
},
fixable: 'code',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { TokenOrComment } from './BinarySearchTree';
*/
export class TokenInfo {
private readonly sourceCode: TSESLint.SourceCode;
public firstTokensByLineNumber: Map<number, TSESTree.Token>;
public readonly firstTokensByLineNumber: Map<number, TSESTree.Token>;

constructor(sourceCode: TSESLint.SourceCode) {
this.sourceCode = sourceCode;
Expand All @@ -28,7 +28,7 @@ export class TokenInfo {
}
return map;
},
new Map(),
new Map<number, TSESTree.Token>(),
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1664,12 +1664,10 @@ export default createRule<Options, MessageIds>({

return commentMap.set(
comment,
commentMap.has(tokenOrCommentBefore)
? commentMap.get(tokenOrCommentBefore)
: tokenOrCommentBefore,
commentMap.get(tokenOrCommentBefore) ?? tokenOrCommentBefore,
);
},
new WeakMap(),
new WeakMap<TokenOrComment, TSESTree.Token>(),
);

sourceCode.lines.forEach((_, lineIndex) => {
Expand Down Expand Up @@ -1700,7 +1698,7 @@ export default createRule<Options, MessageIds>({
}

if (isCommentToken(firstTokenOfLine)) {
const tokenBefore = precedingTokens.get(firstTokenOfLine);
const tokenBefore = precedingTokens.get(firstTokenOfLine)!;
const tokenAfter = tokenBefore
? sourceCode.getTokenAfter(tokenBefore)!
: sourceCode.ast.tokens[0];
Expand Down
4 changes: 2 additions & 2 deletions packages/eslint-plugin/src/rules/indent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* This is due to some really funky type conversions between different node types.
* This is done intentionally based on the internal implementation of the base indent rule.
*/
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment */

import {
TSESTree,
Expand Down Expand Up @@ -396,7 +396,7 @@ export default util.createRule<Options, MessageIds>({
computed: false,
method: false,
shorthand: false,
} as any,
},
],

// location data
Expand Down
6 changes: 3 additions & 3 deletions packages/eslint-plugin/src/rules/naming-convention.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,17 +81,17 @@ export default util.createRule<Options, MessageIds>({
},
defaultOptions: defaultCamelCaseAllTheThingsConfig,
create(contextWithoutDefaults) {
const context: Context =
const context =
contextWithoutDefaults.options &&
contextWithoutDefaults.options.length > 0
? contextWithoutDefaults
: // only apply the defaults when the user provides no config
Object.setPrototypeOf(
(Object.setPrototypeOf(
{
options: defaultCamelCaseAllTheThingsConfig,
},
contextWithoutDefaults,
);
) as Context);

const validators = parseOptions(context);

Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-plugin/src/rules/no-extra-parens.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// any is required to work around manipulating the AST in weird ways
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment */

import {
AST_NODE_TYPES,
Expand Down
4 changes: 2 additions & 2 deletions packages/eslint-plugin/src/rules/unified-signatures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,7 @@ export default util.createRule({

const scopes: Scope[] = [];
let currentScope: Scope = {
overloads: new Map(),
overloads: new Map<string, OverloadNode[]>(),
};

function createScope(
Expand All @@ -480,7 +480,7 @@ export default util.createRule({
): void {
currentScope && scopes.push(currentScope);
currentScope = {
overloads: new Map(),
overloads: new Map<string, OverloadNode[]>(),
parent,
typeParameters,
};
Expand Down
3 changes: 2 additions & 1 deletion packages/eslint-plugin/src/util/createRule.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { ESLintUtils } from '@typescript-eslint/experimental-utils';

// note - cannot migrate this to an import statement because it will make TSC copy the package.json to the dist folder
const version = require('../../package.json').version;
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const version: string = require('../../package.json');

export const createRule = ESLintUtils.RuleCreator(
name =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
/* eslint-disable @typescript-eslint/no-namespace */

import * as eslintUtils from 'eslint-utils';
import { TSESTree } from '../../ts-estree';
import * as TSESLint from '../../ts-eslint';

/* eslint-disable @typescript-eslint/no-unsafe-assignment */
const ReferenceTrackerREAD: unique symbol = eslintUtils.ReferenceTracker.READ;
const ReferenceTrackerCALL: unique symbol = eslintUtils.ReferenceTracker.CALL;
const ReferenceTrackerCONSTRUCT: unique symbol =
eslintUtils.ReferenceTracker.CONSTRUCT;
/* eslint-enable @typescript-eslint/no-unsafe-assignment */
Comment on lines +6 to +11
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went down a bit of a rabbit hole on this one... In theory we could turn them into their own unique symbols, and use typeof ... for the types here.

Unfortunately that then means that the eslint-utils/ReferenceTracker.d.ts output file now has an import from eslint-utils, which causes compile complaints:

Error: @typescript-eslint/eslint-plugin-internal: ../experimental-utils/dist/ast-utils/eslint-utils/ReferenceTracker.d.ts(1,30): error TS7016: Could not find a declaration file for module 'eslint-utils'. '/home/runner/work/typescript-eslint/typescript-eslint/node_modules/eslint-utils/index.js' implicitly has an 'any' type.

At that point I gave up.


interface ReferenceTracker {
/**
Expand Down
8 changes: 4 additions & 4 deletions packages/experimental-utils/src/eslint-utils/applyDefault.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ import { deepMerge, isObjectNotArray } from './deepMerge';
* @returns the options with defaults
*/
function applyDefault<TUser extends readonly unknown[], TDefault extends TUser>(
defaultOptions: TDefault,
userOptions: TUser | null,
defaultOptions: Readonly<TDefault>,
userOptions: Readonly<TUser> | null,
): TDefault {
// clone defaults
const options: AsMutable<TDefault> = JSON.parse(
const options = JSON.parse(
JSON.stringify(defaultOptions),
);
) as AsMutable<TDefault>;

if (userOptions === null || userOptions === undefined) {
return options;
Expand Down
2 changes: 2 additions & 0 deletions packages/experimental-utils/src/ts-eslint-scope/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ export * from './Referencer';
export * from './Scope';
export * from './ScopeManager';
export * from './Variable';

// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
export const version: string = ESLintVersion;
5 changes: 2 additions & 3 deletions packages/experimental-utils/typings/eslint-scope.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ declare module 'eslint-scope/lib/scope-manager' {
export = ScopeManager;
}
declare module 'eslint-scope' {
const version: string;
const analyze: unknown;
export { analyze, version };
export const version: string;
export const analyze: unknown;
}
6 changes: 3 additions & 3 deletions packages/experimental-utils/typings/eslint-utils.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ declare module 'eslint-utils' {
export const isSemicolonToken: unknown;
export const PatternMatcher: unknown;
export const ReferenceTracker: {
READ: never;
CALL: never;
CONSTRUCT: never;
readonly READ: never;
readonly CALL: never;
readonly CONSTRUCT: never;
new (): never;
};
}
1 change: 1 addition & 0 deletions packages/parser/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export {
} from '@typescript-eslint/typescript-estree';

// note - cannot migrate this to an import statement because it will make TSC copy the package.json to the dist folder
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
export const version: string = require('../package.json').version;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps we should add a global type declaration to the project.
Something like

declare module '../package.json' {
  export const version = string;
}

would that fix this problem?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so 😕 , in @types/node/globals.d.ts NodeJS.Require is typed as returning any from its (id: string) function signature.

interface Require {
  (id: string): any;

2 changes: 1 addition & 1 deletion packages/scope-manager/src/scope/GlobalScope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class GlobalScope extends ScopeBase<
constructor(scopeManager: ScopeManager, block: GlobalScope['block']) {
super(scopeManager, ScopeType.global, null, block, false);
this.implicit = {
set: new Map(),
set: new Map<string, Variable>(),
variables: [],
leftToBeResolved: [],
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ function createSerializer<TConstructor extends ConstructorSignature>(
): string {
const id = thing.$id != null ? `$${thing.$id}` : '';
// If `type` is a base class, we should print out the name of the subclass
const constructorName = Object.getPrototypeOf(thing).constructor.name;
// eslint-disable-next-line @typescript-eslint/ban-types
const constructorName = (Object.getPrototypeOf(thing) as Object)
.constructor.name;

if (constructorName === 'ImplicitLibVariable' && thing.name === 'const') {
return 'ImplicitGlobalConstTypeVariable';
Expand Down
4 changes: 1 addition & 3 deletions packages/typescript-estree/src/ast-converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ export function astConverter(
* The TypeScript compiler produced fundamental parse errors when parsing the
* source.
*/
// internal typescript api...
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const parseDiagnostics = (ast as any).parseDiagnostics;
const { parseDiagnostics } = ast;
if (parseDiagnostics.length) {
throw convertError(parseDiagnostics[0]);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/typescript-estree/src/convert.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// There's lots of funny stuff due to the typing of ts.Node
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call */
import * as ts from 'typescript';
import {
canContainDirective,
Expand Down
1 change: 1 addition & 0 deletions packages/typescript-estree/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ export { clearCaches } from './create-program/createWatchProgram';
export { visitorKeys } from '@typescript-eslint/visitor-keys';

// note - cannot migrate this to an import statement because it will make TSC copy the package.json to the dist folder
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
export const version: string = require('../package.json').version;
11 changes: 7 additions & 4 deletions packages/typescript-estree/tests/ast-alignment/parse.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/restrict-plus-operands */
/* eslint-disable @typescript-eslint/no-explicit-any */

import type babelParser from '@babel/parser';
import { ParserPlugin } from '@babel/parser';
import { codeFrameColumns } from '@babel/code-frame';
import type { File } from '@babel/types';
import * as parser from '../../src/parser';
import { TSESTree } from '@typescript-eslint/types';

function createError(
message: string,
Expand All @@ -19,8 +21,8 @@ function createError(
return error;
}

function parseWithBabelParser(text: string, jsx = true): any {
const babel: typeof babelParser = require('@babel/parser');
function parseWithBabelParser(text: string, jsx = true): File {
const babel = require('@babel/parser') as typeof babelParser;
const plugins: ParserPlugin[] = [
'classProperties',
'decorators-legacy',
Expand Down Expand Up @@ -96,7 +98,7 @@ export function parse(
);
}
} catch (error) {
const loc = error.loc;
const loc = error.loc as TSESTree.LineAndColumnData | undefined;
if (loc) {
error.codeFrame = codeFrameColumns(
text,
Expand All @@ -112,6 +114,7 @@ export function parse(
);
error.message += `\n${error.codeFrame}`;
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
result.parseError = error;
}

Expand Down
2 changes: 1 addition & 1 deletion packages/typescript-estree/tests/ast-alignment/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// babel types are something we don't really care about
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/restrict-plus-operands */
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/restrict-plus-operands */
import { AST_NODE_TYPES, TSESTree } from '../../src/ts-estree';
import { deeplyCopy, omitDeep } from '../../tools/test-utils';
import * as BabelTypes from '@babel/types';
Expand Down
1 change: 1 addition & 0 deletions packages/typescript-estree/typings/typescript.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ declare module 'typescript' {
interface SourceFile {
// this is marked as internal to typescript
externalModuleIndicator?: Node;
parseDiagnostics: DiagnosticWithLocation[];
}
}
2 changes: 2 additions & 0 deletions tests/integration/utils/generate-package-json.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment */

const fs = require('fs');
// eslint-disable-next-line import/no-absolute-path
const rootPackageJSON = require('/usr/root-package.json');
Expand Down
4 changes: 2 additions & 2 deletions tools/generate-contributors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ async function* fetchUsers(page = 1): AsyncIterableIterator<Contributor[]> {
const response = await fetch(`${contributorsApiUrl}&page=${page}`, {
method: 'GET',
});
const contributors:
const contributors = (await response.json()) as
| Contributor[]
| { message: string } = await response.json();
| { message: string };

if (!Array.isArray(contributors)) {
throw new Error(contributors.message);
Expand Down