diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 8f8944f970..fd885db02b 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -1,8 +1,17 @@ module.exports = { - extends: 'react-app', + extends: [ + 'react-app', + 'plugin:@typescript-eslint/recommended-type-checked', + 'plugin:@typescript-eslint/stylistic-type-checked' + ], parser: '@typescript-eslint/parser', + parserOptions: { + project: true, + tsconfigRootDir: __dirname + }, + plugins: ['@typescript-eslint'], settings: { @@ -20,8 +29,8 @@ module.exports = { rules: { 'jsx-a11y/href-no-hash': 'off', - 'no-unused-vars': 'off', - '@typescript-eslint/no-unused-expressions': 'off', + + // These off/not-configured-the-way-we-want lint rules we like & opt into '@typescript-eslint/no-unused-vars': [ 'error', { @@ -31,6 +40,33 @@ module.exports = { argsIgnorePattern: '^_', varsIgnorePattern: '^_' } - ] + ], + '@typescript-eslint/restrict-template-expressions': [ + 'error', + { + allowNever: true + } + ], + + // Todo: investigate whether we'd like these on + '@typescript-eslint/ban-ts-comment': 'off', + '@typescript-eslint/ban-types': 'off', + '@typescript-eslint/consistent-indexed-object-style': 'off', + '@typescript-eslint/consistent-type-definitions': 'off', + '@typescript-eslint/no-confusing-void-expression': 'off', + '@typescript-eslint/no-empty-function': 'off', + '@typescript-eslint/no-floating-promises': 'off', + '@typescript-eslint/no-unsafe-argument': 'off', + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/no-unsafe-return': 'off', + '@typescript-eslint/prefer-function-type': 'off', + '@typescript-eslint/sort-type-constituents': 'off', + '@typescript-eslint/unbound-method': 'off', + 'prefer-rest-params': 'off', + + // These lint rules don't make sense for us but are enabled in the preset configs + '@typescript-eslint/no-unused-expressions': 'off' } } diff --git a/package.json b/package.json index 85d6936c91..7d5f0d8991 100644 --- a/package.json +++ b/package.json @@ -59,8 +59,8 @@ "devDependencies": { "@babel/core": "^7.19.0", "@types/node": "^18.7.16", - "@typescript-eslint/eslint-plugin": "^5.36.2", - "@typescript-eslint/parser": "^5.36.2", + "@typescript-eslint/eslint-plugin": "6.0.0-alpha.158", + "@typescript-eslint/parser": "6.0.0-alpha.158", "cross-env": "^7.0.3", "esbuild-extra": "^0.1.3", "eslint": "^8.23.0", @@ -78,5 +78,9 @@ "typescript": "^4.8.3", "vitest": "^0.27.2" }, + "resolutions": { + "@typescript-eslint/eslint-plugin": "6.0.0-alpha.158", + "@typescript-eslint/parser": "6.0.0-alpha.158" + }, "sideEffects": false } diff --git a/src/applyMiddleware.ts b/src/applyMiddleware.ts index 2f1b4752e9..56861943bb 100644 --- a/src/applyMiddleware.ts +++ b/src/applyMiddleware.ts @@ -64,7 +64,7 @@ export default function applyMiddleware( const middlewareAPI: MiddlewareAPI = { getState: store.getState, - dispatch: (action, ...args) => dispatch(action, ...args) + dispatch: (action, ...args: unknown[]) => dispatch(action, ...args) } const chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch) diff --git a/src/combineReducers.ts b/src/combineReducers.ts index 0a3c0b65b4..e8c737f7e2 100644 --- a/src/combineReducers.ts +++ b/src/combineReducers.ts @@ -125,9 +125,7 @@ export default function combineReducers(reducers: { }) { const reducerKeys = Object.keys(reducers) const finalReducers: { [key: string]: Reducer } = {} - for (let i = 0; i < reducerKeys.length; i++) { - const key = reducerKeys[i] - + for (const key of reducerKeys) { if (process.env.NODE_ENV !== 'production') { if (typeof reducers[key] === 'undefined') { warning(`No reducer provided for key "${key}"`) @@ -176,13 +174,12 @@ export default function combineReducers(reducers: { let hasChanged = false const nextState: StateFromReducersMapObject = {} - for (let i = 0; i < finalReducerKeys.length; i++) { - const key = finalReducerKeys[i] + for (const key of finalReducerKeys) { const reducer = finalReducers[key] const previousStateForKey = state[key] const nextStateForKey = reducer(previousStateForKey, action) if (typeof nextStateForKey === 'undefined') { - const actionType = action && action.type + const actionType = action?.type throw new Error( `When called with an action of type ${ actionType ? `"${String(actionType)}"` : '(unknown type)' diff --git a/test/combineReducers.spec.ts b/test/combineReducers.spec.ts index dacb74f833..2f10604d05 100644 --- a/test/combineReducers.spec.ts +++ b/test/combineReducers.spec.ts @@ -15,7 +15,7 @@ describe('Utils', () => { type PushAction = { type: 'push'; value: unknown } const reducer = combineReducers({ - counter: (state: number = 0, action: IncrementAction) => + counter: (state = 0, action: IncrementAction) => action.type === 'increment' ? state + 1 : state, stack: (state: any[] = [], action: PushAction) => action.type === 'push' ? [...state, action.value] : state @@ -64,8 +64,8 @@ describe('Utils', () => { it('throws an error if a reducer returns undefined handling an action', () => { const reducer = combineReducers({ - counter(state: number = 0, action: Action) { - switch (action && action.type) { + counter(state = 0, action: Action) { + switch (action?.type) { case 'increment': return state + 1 case 'decrement': diff --git a/test/createStore.spec.ts b/test/createStore.spec.ts index c3d3a06bad..9d32c56540 100644 --- a/test/createStore.spec.ts +++ b/test/createStore.spec.ts @@ -431,7 +431,7 @@ describe('createStore', () => { const store = createStore(reducers.todos) let resolve: (value: unknown) => void = () => {} - let promise = new Promise(_resolve => { + const promise = new Promise(_resolve => { resolve = _resolve }) store.subscribe(() => { @@ -451,7 +451,7 @@ describe('createStore', () => { it('does not leak private listeners array', async () => { const store = createStore(reducers.todos) let resolve: (value: unknown) => void = () => {} - let promise = new Promise(_resolve => { + const promise = new Promise(_resolve => { resolve = _resolve }) diff --git a/test/typescript/actions.ts b/test/typescript/actions.ts index 0f1e37e94c..0a4fac56f8 100644 --- a/test/typescript/actions.ts +++ b/test/typescript/actions.ts @@ -23,7 +23,7 @@ namespace FreeShapeAction { text: 'test' } - const text: string = action['text'] + const text: string = action.text } namespace StringLiteralTypeAction { diff --git a/test/typescript/store.ts b/test/typescript/store.ts index 1cac024118..d556e2aedd 100644 --- a/test/typescript/store.ts +++ b/test/typescript/store.ts @@ -101,10 +101,10 @@ const storeWithCombineReducerAndBadPreloadedState = createStore( ) const nestedCombinedReducer = combineReducers({ - a: (state: string = 'a') => state, + a: (state = 'a') => state, b: combineReducers({ - c: (state: string = 'c') => state, - d: (state: string = 'd') => state + c: (state = 'c') => state, + d: (state = 'd') => state }), e: (state: BrandedString = brandedString) => state }) @@ -116,8 +116,8 @@ const storeWithNestedCombineReducer = createStore(nestedCombinedReducer, { }) const simpleCombinedReducer = combineReducers({ - c: (state: string = 'c') => state, - d: (state: string = 'd') => state + c: (state = 'c') => state, + d: (state = 'd') => state }) // @ts-expect-error diff --git a/yarn.lock b/yarn.lock index d230d94b77..5c7ccaf4d1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1762,6 +1762,24 @@ __metadata: languageName: node linkType: hard +"@eslint-community/eslint-utils@npm:^4.3.0": + version: 4.4.0 + resolution: "@eslint-community/eslint-utils@npm:4.4.0" + dependencies: + eslint-visitor-keys: ^3.3.0 + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + checksum: cdfe3ae42b4f572cbfb46d20edafe6f36fc5fb52bf2d90875c58aefe226892b9677fef60820e2832caf864a326fe4fc225714c46e8389ccca04d5f9288aabd22 + languageName: node + linkType: hard + +"@eslint-community/regexpp@npm:^4.5.0": + version: 4.5.1 + resolution: "@eslint-community/regexpp@npm:4.5.1" + checksum: 6d901166d64998d591fab4db1c2f872981ccd5f6fe066a1ad0a93d4e11855ecae6bfb76660869a469563e8882d4307228cebd41142adb409d182f2966771e57e + languageName: node + linkType: hard + "@eslint/eslintrc@npm:^1.4.1": version: 1.4.1 resolution: "@eslint/eslintrc@npm:1.4.1" @@ -1963,6 +1981,13 @@ __metadata: languageName: node linkType: hard +"@types/json-schema@npm:^7.0.11": + version: 7.0.12 + resolution: "@types/json-schema@npm:7.0.12" + checksum: 00239e97234eeb5ceefb0c1875d98ade6e922bfec39dd365ec6bd360b5c2f825e612ac4f6e5f1d13601b8b30f378f15e6faa805a3a732f4a1bbe61915163d293 + languageName: node + linkType: hard + "@types/json-schema@npm:^7.0.9": version: 7.0.11 resolution: "@types/json-schema@npm:7.0.11" @@ -1998,27 +2023,27 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:^5.36.2, @typescript-eslint/eslint-plugin@npm:^5.5.0": - version: 5.51.0 - resolution: "@typescript-eslint/eslint-plugin@npm:5.51.0" +"@typescript-eslint/eslint-plugin@npm:6.0.0-alpha.158": + version: 6.0.0-alpha.158 + resolution: "@typescript-eslint/eslint-plugin@npm:6.0.0-alpha.158" dependencies: - "@typescript-eslint/scope-manager": 5.51.0 - "@typescript-eslint/type-utils": 5.51.0 - "@typescript-eslint/utils": 5.51.0 + "@eslint-community/regexpp": ^4.5.0 + "@typescript-eslint/scope-manager": 6.0.0-alpha.158+b411706a1 + "@typescript-eslint/type-utils": 6.0.0-alpha.158+b411706a1 + "@typescript-eslint/utils": 6.0.0-alpha.158+b411706a1 debug: ^4.3.4 grapheme-splitter: ^1.0.4 - ignore: ^5.2.0 - natural-compare-lite: ^1.4.0 - regexpp: ^3.2.0 - semver: ^7.3.7 - tsutils: ^3.21.0 + ignore: ^5.2.4 + natural-compare: ^1.4.0 + semver: ^7.5.0 + ts-api-utils: ^1.0.0 peerDependencies: - "@typescript-eslint/parser": ^5.0.0 - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + "@typescript-eslint/parser": ^6.0.0 || ^6.0.0-alpha + eslint: ^7.0.0 || ^8.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 5351d8cec13bd9867ce4aaf7052aa31c9ca867fc89c620fc0fe5718ac2cbc165903275db59974324d98e45df0d33a73a4367d236668772912731031a672cfdcd + checksum: 8d91730a682de7b22d2f45367fcb2ba5a65f05f34f32598751b7c73f8a36c11a7d60be9282018bbc8ca4db1e370066c710000ec0cd45fe7c63231f65dc473afa languageName: node linkType: hard @@ -2033,20 +2058,21 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/parser@npm:^5.36.2, @typescript-eslint/parser@npm:^5.5.0": - version: 5.51.0 - resolution: "@typescript-eslint/parser@npm:5.51.0" +"@typescript-eslint/parser@npm:6.0.0-alpha.158": + version: 6.0.0-alpha.158 + resolution: "@typescript-eslint/parser@npm:6.0.0-alpha.158" dependencies: - "@typescript-eslint/scope-manager": 5.51.0 - "@typescript-eslint/types": 5.51.0 - "@typescript-eslint/typescript-estree": 5.51.0 + "@typescript-eslint/scope-manager": 6.0.0-alpha.158+b411706a1 + "@typescript-eslint/types": 6.0.0-alpha.158+b411706a1 + "@typescript-eslint/typescript-estree": 6.0.0-alpha.158+b411706a1 + "@typescript-eslint/visitor-keys": 6.0.0-alpha.158+b411706a1 debug: ^4.3.4 peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + eslint: ^7.0.0 || ^8.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 096ec819132839febd4f390c4bbf31687e06191092c244dbd189a64cd7383fbaba728f2765e8809cd9834c0069163ab38b0e5f0f6360157d831647d4c295f8cd + checksum: 72976052e081ba3b36869065af5773c9e52a2049639a45453154c639b0ef4f87cff59d127b3e395230a226b95890c8e043a4bb39e6b1fed27799a07f5016a0de languageName: node linkType: hard @@ -2060,20 +2086,30 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:5.51.0": - version: 5.51.0 - resolution: "@typescript-eslint/type-utils@npm:5.51.0" +"@typescript-eslint/scope-manager@npm:6.0.0-alpha.158+b411706a1": + version: 6.0.0-alpha.158 + resolution: "@typescript-eslint/scope-manager@npm:6.0.0-alpha.158" dependencies: - "@typescript-eslint/typescript-estree": 5.51.0 - "@typescript-eslint/utils": 5.51.0 + "@typescript-eslint/types": 6.0.0-alpha.158+b411706a1 + "@typescript-eslint/visitor-keys": 6.0.0-alpha.158+b411706a1 + checksum: 1ba92a6240dbbfc515a3b0895e893ecfde466b24f92de63c7d248308a7dddbecdc1a9b47c6e8cfd4f6ffb70413a183e10029542e016884c3db812413e2ccdd26 + languageName: node + linkType: hard + +"@typescript-eslint/type-utils@npm:6.0.0-alpha.158+b411706a1": + version: 6.0.0-alpha.158 + resolution: "@typescript-eslint/type-utils@npm:6.0.0-alpha.158" + dependencies: + "@typescript-eslint/typescript-estree": 6.0.0-alpha.158+b411706a1 + "@typescript-eslint/utils": 6.0.0-alpha.158+b411706a1 debug: ^4.3.4 - tsutils: ^3.21.0 + ts-api-utils: ^1.0.0 peerDependencies: - eslint: "*" + eslint: ^7.0.0 || ^8.0.0 peerDependenciesMeta: typescript: optional: true - checksum: ab9747b0c629cfaaab903eed8ce1e39d34d69a402ce5faf2f1fff2bbb461bdbe034044b1368ba67ba8e5c1c512172e07d83c8a563635d8de811bf148d95c7dec + checksum: 944df9686c012e7d69f587253cc1eb15f2cb5b55369c2b4ebf172f1e352756355aa561401abc2d99d69f27ff8fcd3bcffe06295f3146656420f6b2f1b3b24eeb languageName: node linkType: hard @@ -2084,6 +2120,13 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/types@npm:6.0.0-alpha.158+b411706a1": + version: 6.0.0-alpha.158 + resolution: "@typescript-eslint/types@npm:6.0.0-alpha.158" + checksum: 3ad4b14505a7d5092d0ae03969b381dcad57dfbbf40b027a41a16f5fc1bff47e6449bc05d476fbb5f13aac7240f6515ef6fce35115a36fafd2bed8c09b5ccab3 + languageName: node + linkType: hard + "@typescript-eslint/typescript-estree@npm:5.51.0": version: 5.51.0 resolution: "@typescript-eslint/typescript-estree@npm:5.51.0" @@ -2102,6 +2145,24 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/typescript-estree@npm:6.0.0-alpha.158+b411706a1": + version: 6.0.0-alpha.158 + resolution: "@typescript-eslint/typescript-estree@npm:6.0.0-alpha.158" + dependencies: + "@typescript-eslint/types": 6.0.0-alpha.158+b411706a1 + "@typescript-eslint/visitor-keys": 6.0.0-alpha.158+b411706a1 + debug: ^4.3.4 + globby: ^11.1.0 + is-glob: ^4.0.3 + semver: ^7.5.0 + ts-api-utils: ^1.0.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: c124fe574181627f142ef41e2938d7e82a139349f91427d2efeef452b1c604e61dc61c72171fdd642b718258b25fd71b5b41abcb880637bf0f47c877ab890a44 + languageName: node + linkType: hard + "@typescript-eslint/utils@npm:5.51.0, @typescript-eslint/utils@npm:^5.43.0": version: 5.51.0 resolution: "@typescript-eslint/utils@npm:5.51.0" @@ -2120,6 +2181,24 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/utils@npm:6.0.0-alpha.158+b411706a1": + version: 6.0.0-alpha.158 + resolution: "@typescript-eslint/utils@npm:6.0.0-alpha.158" + dependencies: + "@eslint-community/eslint-utils": ^4.3.0 + "@types/json-schema": ^7.0.11 + "@types/semver": ^7.3.12 + "@typescript-eslint/scope-manager": 6.0.0-alpha.158+b411706a1 + "@typescript-eslint/types": 6.0.0-alpha.158+b411706a1 + "@typescript-eslint/typescript-estree": 6.0.0-alpha.158+b411706a1 + eslint-scope: ^5.1.1 + semver: ^7.5.0 + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + checksum: a5bed5c4f40416f197bdc3e90926bce99a786b700cce15f9b6c5a55fc4cdba18bc64b52a62e4e9864b4963ef6eb3d8afa0c85b41345e376c6fc02c9361082798 + languageName: node + linkType: hard + "@typescript-eslint/visitor-keys@npm:5.51.0": version: 5.51.0 resolution: "@typescript-eslint/visitor-keys@npm:5.51.0" @@ -2130,6 +2209,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/visitor-keys@npm:6.0.0-alpha.158+b411706a1": + version: 6.0.0-alpha.158 + resolution: "@typescript-eslint/visitor-keys@npm:6.0.0-alpha.158" + dependencies: + "@typescript-eslint/types": 6.0.0-alpha.158+b411706a1 + eslint-visitor-keys: ^3.4.1 + checksum: e8940eeac6740f8cd6a70130cffc0ae0b723e0a27ee342e2d860642d0ca26aa1be8738f554d83b9e100364b2a7944dee3f520511ac50868a1c54036af8233eef + languageName: node + linkType: hard + "abbrev@npm:^1.0.0": version: 1.1.1 resolution: "abbrev@npm:1.1.1" @@ -3489,6 +3578,13 @@ __metadata: languageName: node linkType: hard +"eslint-visitor-keys@npm:^3.4.1": + version: 3.4.1 + resolution: "eslint-visitor-keys@npm:3.4.1" + checksum: f05121d868202736b97de7d750847a328fcfa8593b031c95ea89425333db59676ac087fa905eba438d0a3c5769632f828187e0c1a0d271832a2153c1d3661c2c + languageName: node + linkType: hard + "eslint@npm:^8.23.0": version: 8.34.0 resolution: "eslint@npm:8.34.0" @@ -4098,7 +4194,7 @@ __metadata: languageName: node linkType: hard -"ignore@npm:^5.2.0": +"ignore@npm:^5.2.0, ignore@npm:^5.2.4": version: 5.2.4 resolution: "ignore@npm:5.2.4" checksum: 3d4c309c6006e2621659311783eaea7ebcd41fe4ca1d78c91c473157ad6666a57a2df790fe0d07a12300d9aac2888204d7be8d59f9aaf665b1c7fcdb432517ef @@ -4897,13 +4993,6 @@ __metadata: languageName: node linkType: hard -"natural-compare-lite@npm:^1.4.0": - version: 1.4.0 - resolution: "natural-compare-lite@npm:1.4.0" - checksum: 5222ac3986a2b78dd6069ac62cbb52a7bf8ffc90d972ab76dfe7b01892485d229530ed20d0c62e79a6b363a663b273db3bde195a1358ce9e5f779d4453887225 - languageName: node - linkType: hard - "natural-compare@npm:^1.4.0": version: 1.4.0 resolution: "natural-compare@npm:1.4.0" @@ -5376,8 +5465,8 @@ __metadata: dependencies: "@babel/core": ^7.19.0 "@types/node": ^18.7.16 - "@typescript-eslint/eslint-plugin": ^5.36.2 - "@typescript-eslint/parser": ^5.36.2 + "@typescript-eslint/eslint-plugin": 6.0.0-alpha.158 + "@typescript-eslint/parser": 6.0.0-alpha.158 cross-env: ^7.0.3 esbuild-extra: ^0.1.3 eslint: ^8.23.0 @@ -5654,6 +5743,17 @@ __metadata: languageName: node linkType: hard +"semver@npm:^7.5.0": + version: 7.5.2 + resolution: "semver@npm:7.5.2" + dependencies: + lru-cache: ^6.0.0 + bin: + semver: bin/semver.js + checksum: 3fdf5d1e6f170fe8bcc41669e31787649af91af7f54f05c71d0865bb7aa27e8b92f68b3e6b582483e2c1c648008bc84249d2cd86301771fe5cbf7621d1fe5375 + languageName: node + linkType: hard + "set-blocking@npm:^2.0.0": version: 2.0.0 resolution: "set-blocking@npm:2.0.0" @@ -6076,6 +6176,15 @@ __metadata: languageName: node linkType: hard +"ts-api-utils@npm:^1.0.0": + version: 1.0.1 + resolution: "ts-api-utils@npm:1.0.1" + peerDependencies: + typescript: ">=4.2.0" + checksum: 78794fc7270d295b36c1ac613465b5dc7e7226907a533125b30f177efef9dd630d4e503b00be31b44335eb2ebf9e136ebe97353f8fc5d383885d5fead9d54c09 + languageName: node + linkType: hard + "ts-interface-checker@npm:^0.1.9": version: 0.1.13 resolution: "ts-interface-checker@npm:0.1.13"