Skip to content

Commit 2c92c7c

Browse files
authored
Add typescript guideline and typescript-specific eslint plugins and fix issues (#31521)
1. Add some general guidelines how to write our typescript code 2. Add `@typescript-eslint/eslint-plugin`, general typescript rules 3. Add `eslint-plugin-deprecation` to detect deprecated code 4. Fix all new lint issues that came up
1 parent b270b30 commit 2c92c7c

File tree

11 files changed

+226
-151
lines changed

11 files changed

+226
-151
lines changed

.eslintrc.yaml

+127-6
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ parserOptions:
1313
ecmaVersion: latest
1414
project: true
1515
extraFileExtensions: [".vue"]
16+
parser: "@typescript-eslint/parser" # for vue plugin - https://eslint.vuejs.org/user-guide/#how-to-use-a-custom-parser
1617

1718
settings:
1819
import/extensions: [".js", ".ts"]
@@ -24,7 +25,9 @@ settings:
2425
plugins:
2526
- "@eslint-community/eslint-plugin-eslint-comments"
2627
- "@stylistic/eslint-plugin-js"
28+
- "@typescript-eslint/eslint-plugin"
2729
- eslint-plugin-array-func
30+
- eslint-plugin-deprecation
2831
- eslint-plugin-github
2932
- eslint-plugin-i
3033
- eslint-plugin-no-jquery
@@ -209,6 +212,123 @@ rules:
209212
"@stylistic/js/wrap-iife": [2, inside]
210213
"@stylistic/js/wrap-regex": [0]
211214
"@stylistic/js/yield-star-spacing": [2, after]
215+
"@typescript-eslint/adjacent-overload-signatures": [0]
216+
"@typescript-eslint/array-type": [0]
217+
"@typescript-eslint/await-thenable": [2]
218+
"@typescript-eslint/ban-ts-comment": [2, {'ts-expect-error': false, 'ts-ignore': true, 'ts-nocheck': false, 'ts-check': false}]
219+
"@typescript-eslint/ban-tslint-comment": [0]
220+
"@typescript-eslint/ban-types": [2, {extendDefaults: true, types: {Function: false}}]
221+
"@typescript-eslint/class-literal-property-style": [0]
222+
"@typescript-eslint/class-methods-use-this": [0]
223+
"@typescript-eslint/consistent-generic-constructors": [0]
224+
"@typescript-eslint/consistent-indexed-object-style": [0]
225+
"@typescript-eslint/consistent-return": [0]
226+
"@typescript-eslint/consistent-type-assertions": [2, {assertionStyle: as, objectLiteralTypeAssertions: allow}]
227+
"@typescript-eslint/consistent-type-definitions": [2, type]
228+
"@typescript-eslint/consistent-type-exports": [2, {fixMixedExportsWithInlineTypeSpecifier: false}]
229+
"@typescript-eslint/consistent-type-imports": [2, {prefer: type-imports, fixStyle: separate-type-imports, disallowTypeAnnotations: true}]
230+
"@typescript-eslint/default-param-last": [0]
231+
"@typescript-eslint/dot-notation": [0]
232+
"@typescript-eslint/explicit-function-return-type": [0]
233+
"@typescript-eslint/explicit-member-accessibility": [0]
234+
"@typescript-eslint/explicit-module-boundary-types": [0]
235+
"@typescript-eslint/init-declarations": [0]
236+
"@typescript-eslint/max-params": [0]
237+
"@typescript-eslint/member-ordering": [0]
238+
"@typescript-eslint/method-signature-style": [0]
239+
"@typescript-eslint/naming-convention": [0]
240+
"@typescript-eslint/no-array-constructor": [2]
241+
"@typescript-eslint/no-array-delete": [2]
242+
"@typescript-eslint/no-base-to-string": [0]
243+
"@typescript-eslint/no-confusing-non-null-assertion": [2]
244+
"@typescript-eslint/no-confusing-void-expression": [0]
245+
"@typescript-eslint/no-dupe-class-members": [0]
246+
"@typescript-eslint/no-duplicate-enum-values": [2]
247+
"@typescript-eslint/no-duplicate-type-constituents": [2, {ignoreUnions: true}]
248+
"@typescript-eslint/no-dynamic-delete": [0]
249+
"@typescript-eslint/no-empty-function": [0]
250+
"@typescript-eslint/no-empty-interface": [0]
251+
"@typescript-eslint/no-explicit-any": [0]
252+
"@typescript-eslint/no-extra-non-null-assertion": [2]
253+
"@typescript-eslint/no-extraneous-class": [0]
254+
"@typescript-eslint/no-floating-promises": [0]
255+
"@typescript-eslint/no-for-in-array": [2]
256+
"@typescript-eslint/no-implied-eval": [2]
257+
"@typescript-eslint/no-import-type-side-effects": [0] # dupe with consistent-type-imports
258+
"@typescript-eslint/no-inferrable-types": [0]
259+
"@typescript-eslint/no-invalid-this": [0]
260+
"@typescript-eslint/no-invalid-void-type": [0]
261+
"@typescript-eslint/no-loop-func": [0]
262+
"@typescript-eslint/no-loss-of-precision": [2]
263+
"@typescript-eslint/no-magic-numbers": [0]
264+
"@typescript-eslint/no-meaningless-void-operator": [0]
265+
"@typescript-eslint/no-misused-new": [2]
266+
"@typescript-eslint/no-misused-promises": [2, {checksVoidReturn: {attributes: false, arguments: false}}]
267+
"@typescript-eslint/no-mixed-enums": [0]
268+
"@typescript-eslint/no-namespace": [2]
269+
"@typescript-eslint/no-non-null-asserted-nullish-coalescing": [0]
270+
"@typescript-eslint/no-non-null-asserted-optional-chain": [2]
271+
"@typescript-eslint/no-non-null-assertion": [0]
272+
"@typescript-eslint/no-redeclare": [0]
273+
"@typescript-eslint/no-redundant-type-constituents": [2]
274+
"@typescript-eslint/no-require-imports": [0]
275+
"@typescript-eslint/no-restricted-imports": [0]
276+
"@typescript-eslint/no-shadow": [0]
277+
"@typescript-eslint/no-this-alias": [0] # handled by unicorn/no-this-assignment
278+
"@typescript-eslint/no-unnecessary-boolean-literal-compare": [0]
279+
"@typescript-eslint/no-unnecessary-condition": [0]
280+
"@typescript-eslint/no-unnecessary-qualifier": [0]
281+
"@typescript-eslint/no-unnecessary-template-expression": [0]
282+
"@typescript-eslint/no-unnecessary-type-arguments": [0]
283+
"@typescript-eslint/no-unnecessary-type-assertion": [2]
284+
"@typescript-eslint/no-unnecessary-type-constraint": [2]
285+
"@typescript-eslint/no-unsafe-argument": [0]
286+
"@typescript-eslint/no-unsafe-assignment": [0]
287+
"@typescript-eslint/no-unsafe-call": [0]
288+
"@typescript-eslint/no-unsafe-declaration-merging": [2]
289+
"@typescript-eslint/no-unsafe-enum-comparison": [2]
290+
"@typescript-eslint/no-unsafe-member-access": [0]
291+
"@typescript-eslint/no-unsafe-return": [0]
292+
"@typescript-eslint/no-unsafe-unary-minus": [2]
293+
"@typescript-eslint/no-unused-expressions": [0]
294+
"@typescript-eslint/no-unused-vars": [2, {vars: all, args: all, caughtErrors: all, ignoreRestSiblings: false, argsIgnorePattern: ^_, varsIgnorePattern: ^_, caughtErrorsIgnorePattern: ^_, destructuredArrayIgnorePattern: ^_}]
295+
"@typescript-eslint/no-use-before-define": [0]
296+
"@typescript-eslint/no-useless-constructor": [0]
297+
"@typescript-eslint/no-useless-empty-export": [0]
298+
"@typescript-eslint/no-var-requires": [2]
299+
"@typescript-eslint/non-nullable-type-assertion-style": [0]
300+
"@typescript-eslint/only-throw-error": [2]
301+
"@typescript-eslint/parameter-properties": [0]
302+
"@typescript-eslint/prefer-as-const": [2]
303+
"@typescript-eslint/prefer-destructuring": [0]
304+
"@typescript-eslint/prefer-enum-initializers": [0]
305+
"@typescript-eslint/prefer-find": [2]
306+
"@typescript-eslint/prefer-for-of": [2]
307+
"@typescript-eslint/prefer-function-type": [2]
308+
"@typescript-eslint/prefer-includes": [2]
309+
"@typescript-eslint/prefer-literal-enum-member": [0]
310+
"@typescript-eslint/prefer-namespace-keyword": [0]
311+
"@typescript-eslint/prefer-nullish-coalescing": [0]
312+
"@typescript-eslint/prefer-optional-chain": [2, {requireNullish: true}]
313+
"@typescript-eslint/prefer-promise-reject-errors": [0]
314+
"@typescript-eslint/prefer-readonly": [0]
315+
"@typescript-eslint/prefer-readonly-parameter-types": [0]
316+
"@typescript-eslint/prefer-reduce-type-parameter": [0]
317+
"@typescript-eslint/prefer-regexp-exec": [0]
318+
"@typescript-eslint/prefer-return-this-type": [0]
319+
"@typescript-eslint/prefer-string-starts-ends-with": [2, {allowSingleElementEquality: always}]
320+
"@typescript-eslint/promise-function-async": [0]
321+
"@typescript-eslint/require-array-sort-compare": [0]
322+
"@typescript-eslint/require-await": [0]
323+
"@typescript-eslint/restrict-plus-operands": [2]
324+
"@typescript-eslint/restrict-template-expressions": [0]
325+
"@typescript-eslint/return-await": [0]
326+
"@typescript-eslint/strict-boolean-expressions": [0]
327+
"@typescript-eslint/switch-exhaustiveness-check": [0]
328+
"@typescript-eslint/triple-slash-reference": [2]
329+
"@typescript-eslint/typedef": [0]
330+
"@typescript-eslint/unbound-method": [2]
331+
"@typescript-eslint/unified-signatures": [2]
212332
accessor-pairs: [2]
213333
array-callback-return: [2, {checkForEach: true}]
214334
array-func/avoid-reverse: [2]
@@ -230,6 +350,7 @@ rules:
230350
default-case-last: [2]
231351
default-case: [0]
232352
default-param-last: [0]
353+
deprecation/deprecation: [2]
233354
dot-notation: [0]
234355
eqeqeq: [2]
235356
for-direction: [2]
@@ -321,7 +442,7 @@ rules:
321442
multiline-comment-style: [2, separate-lines]
322443
new-cap: [0]
323444
no-alert: [0]
324-
no-array-constructor: [2]
445+
no-array-constructor: [0] # handled by @typescript-eslint/no-array-constructor
325446
no-async-promise-executor: [0]
326447
no-await-in-loop: [0]
327448
no-bitwise: [0]
@@ -365,7 +486,7 @@ rules:
365486
no-global-assign: [2]
366487
no-implicit-coercion: [2]
367488
no-implicit-globals: [0]
368-
no-implied-eval: [2]
489+
no-implied-eval: [0] # handled by @typescript-eslint/no-implied-eval
369490
no-import-assign: [2]
370491
no-inline-comments: [0]
371492
no-inner-declarations: [2]
@@ -471,7 +592,7 @@ rules:
471592
no-lone-blocks: [2]
472593
no-lonely-if: [0]
473594
no-loop-func: [0]
474-
no-loss-of-precision: [2]
595+
no-loss-of-precision: [0] # handled by @typescript-eslint/no-loss-of-precision
475596
no-magic-numbers: [0]
476597
no-misleading-character-class: [2]
477598
no-multi-assign: [0]
@@ -493,7 +614,7 @@ rules:
493614
no-promise-executor-return: [0]
494615
no-proto: [2]
495616
no-prototype-builtins: [2]
496-
no-redeclare: [2]
617+
no-redeclare: [0] # must be disabled for typescript overloads
497618
no-regex-spaces: [2]
498619
no-restricted-exports: [0]
499620
no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, location, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, self, status, statusbar, stop, toolbar, top, __dirname, __filename]
@@ -526,7 +647,7 @@ rules:
526647
no-unused-expressions: [2]
527648
no-unused-labels: [2]
528649
no-unused-private-class-members: [2]
529-
no-unused-vars: [2, {args: all, argsIgnorePattern: ^_, varsIgnorePattern: ^_, caughtErrorsIgnorePattern: ^_, destructuredArrayIgnorePattern: ^_, ignoreRestSiblings: false}]
650+
no-unused-vars: [0] # handled by @typescript-eslint/no-unused-vars
530651
no-use-before-define: [2, {functions: false, classes: true, variables: true, allowNamedExports: true}]
531652
no-use-extend-native/no-use-extend-native: [2]
532653
no-useless-backreference: [2]
@@ -641,7 +762,7 @@ rules:
641762
regexp/unicode-escape: [0]
642763
regexp/use-ignore-case: [0]
643764
require-atomic-updates: [0]
644-
require-await: [0]
765+
require-await: [0] # handled by @typescript-eslint/require-await
645766
require-unicode-regexp: [0]
646767
require-yield: [2]
647768
sonarjs/cognitive-complexity: [0]

docs/content/contributing/guidelines-frontend.en-us.md

+16
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,22 @@ We use htmx for simple interactions. You can see an example for simple interacti
7979
Although mixing different frameworks is discouraged,
8080
it should also work if the mixing is necessary and the code is well-designed and maintainable.
8181

82+
### Typescript
83+
84+
Gitea is in the process of migrating to type-safe Typescript. Here are some specific guidelines regarding Typescript in the codebase:
85+
86+
#### Use type aliases instead of interfaces
87+
88+
Prefer to use type aliases because they can represent any type and are generally more flexible to use than interfaces.
89+
90+
#### Use separate type imports
91+
92+
We use `verbatimModuleSyntax` so type and non-type imports from the same file must be split into two `import type` statements. This enables the typescript compiler to completely eliminate the type import statements during compilation.
93+
94+
#### Use `@ts-expect-error` instead of `@ts-ignore`
95+
96+
Both annotations should be avoided, but if you have to use them, use `@ts-expect-error` because it will not leave ineffective statements after the issue is fixed.
97+
8298
### `async` Functions
8399

84100
Only mark a function as `async` if and only if there are `await` calls

0 commit comments

Comments
 (0)