diff --git a/apps/oxlint/fixtures/tsgolint/.oxlintrc.json b/apps/oxlint/fixtures/tsgolint/.oxlintrc.json index c3f3a5015e032..3bf88458c5894 100644 --- a/apps/oxlint/fixtures/tsgolint/.oxlintrc.json +++ b/apps/oxlint/fixtures/tsgolint/.oxlintrc.json @@ -3,7 +3,45 @@ "correctness": "off" }, "rules": { + "typescript/await-thenable": "error", + "typescript/no-array-delete": "error", + "typescript/no-base-to-string": "error", + "typescript/no-confusing-void-expression": "error", + "typescript/no-duplicate-type-constituents": "error", "typescript/no-floating-promises": "error", + "typescript/no-for-in-array": "error", + "typescript/no-implied-eval": "error", + "typescript/no-meaningless-void-operator": "error", + "typescript/no-misused-spread": "error", + "typescript/no-mixed-enums": "error", + "typescript/no-redundant-type-constituents": "error", + "typescript/no-unnecessary-boolean-literal-compare": "error", + "typescript/no-unnecessary-template-expression": "error", + "typescript/no-unnecessary-type-arguments": "error", + "typescript/no-unnecessary-type-assertion": "error", + "typescript/no-unsafe-argument": "error", + "typescript/no-unsafe-assignment": "error", + "typescript/no-unsafe-call": "error", + "typescript/no-unsafe-enum-comparison": "error", + "typescript/no-unsafe-member-access": "error", + "typescript/no-unsafe-return": "error", + "typescript/no-unsafe-type-assertion": "error", + "typescript/no-unsafe-unary-minus": "error", + "typescript/non-nullable-type-assertion-style": "error", + "typescript/only-throw-error": "error", + "typescript/prefer-promise-reject-errors": "error", + "typescript/prefer-reduce-type-parameter": "error", + "typescript/prefer-return-this-type": "error", + "typescript/promise-function-async": "error", + "typescript/related-getter-setter-pairs": "error", + "typescript/require-array-sort-compare": "error", + "typescript/require-await": "error", + "typescript/restrict-plus-operands": "error", + "typescript/restrict-template-expressions": "error", + "typescript/return-await": "error", + "typescript/switch-exhaustiveness-check": "error", + "typescript/unbound-method": "error", + "typescript/use-unknown-in-catch-callback-variable": "error", "no-debugger": "error" } } diff --git a/apps/oxlint/fixtures/tsgolint/await-thenable/index.ts b/apps/oxlint/fixtures/tsgolint/await-thenable/index.ts new file mode 100644 index 0000000000000..032a8c1ee3080 --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/await-thenable/index.ts @@ -0,0 +1,12 @@ +// Examples of incorrect code for await-thenable rule + +await 12; +await (() => {}); + +// non-Promise values +await Math.random; +await { then() {} }; + +// this is not a Promise - it's a function that returns a Promise +declare const getPromise: () => Promise; +await getPromise; \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/no-array-delete/index.ts b/apps/oxlint/fixtures/tsgolint/no-array-delete/index.ts new file mode 100644 index 0000000000000..8b761a73ff952 --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/no-array-delete/index.ts @@ -0,0 +1,4 @@ +// Examples of incorrect code for no-array-delete rule + +declare const arr: number[]; +delete arr[0]; \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/no-base-to-string/index.ts b/apps/oxlint/fixtures/tsgolint/no-base-to-string/index.ts new file mode 100644 index 0000000000000..7eb8b1b32733f --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/no-base-to-string/index.ts @@ -0,0 +1,9 @@ +// Examples of incorrect code for no-base-to-string rule + +// These will evaluate to '[object Object]' +({}).toString(); +({foo: 'bar'}).toString(); +({foo: 'bar'}).toLocaleString(); + +// This will evaluate to 'Symbol()' +Symbol('foo').toString(); \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/no-confusing-void-expression/index.ts b/apps/oxlint/fixtures/tsgolint/no-confusing-void-expression/index.ts new file mode 100644 index 0000000000000..784c28cfb4715 --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/no-confusing-void-expression/index.ts @@ -0,0 +1,12 @@ +// Examples of incorrect code for no-confusing-void-expression rule + +// arrow function returning void expression +const foo = () => void bar(); + +// conditional expression +const result = condition ? void foo() : bar(); + +// void in conditional +if (void foo()) { + // ... +} \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/no-duplicate-type-constituents/index.ts b/apps/oxlint/fixtures/tsgolint/no-duplicate-type-constituents/index.ts new file mode 100644 index 0000000000000..c06f80ed62e2f --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/no-duplicate-type-constituents/index.ts @@ -0,0 +1,14 @@ +// Examples of incorrect code for no-duplicate-type-constituents rule + +type T1 = 'A' | 'A'; + +type T2 = A | A | B; + +type T3 = { a: string } & { a: string }; + +type T4 = [A, A]; + +type T5 = + | 'foo' + | 'bar' + | 'foo'; \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/no-for-in-array/index.ts b/apps/oxlint/fixtures/tsgolint/no-for-in-array/index.ts new file mode 100644 index 0000000000000..5c1c131bc70a3 --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/no-for-in-array/index.ts @@ -0,0 +1,11 @@ +// Examples of incorrect code for no-for-in-array rule + +const arr = [1, 2, 3]; + +for (const i in arr) { + console.log(arr[i]); +} + +for (const i in arr) { + console.log(i, arr[i]); +} \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/no-implied-eval/index.ts b/apps/oxlint/fixtures/tsgolint/no-implied-eval/index.ts new file mode 100644 index 0000000000000..91cd01580d930 --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/no-implied-eval/index.ts @@ -0,0 +1,13 @@ +// Examples of incorrect code for no-implied-eval rule + +setTimeout('alert("Hi!");', 100); + +setInterval('alert("Hi!");', 100); + +setImmediate('alert("Hi!")'); + +window.setTimeout('count = 5', 10); + +window.setInterval('foo = bar', 10); + +const fn = new Function('a', 'b', 'return a + b'); \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/no-meaningless-void-operator/index.ts b/apps/oxlint/fixtures/tsgolint/no-meaningless-void-operator/index.ts new file mode 100644 index 0000000000000..9a85b893c00ab --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/no-meaningless-void-operator/index.ts @@ -0,0 +1,13 @@ +// Examples of incorrect code for no-meaningless-void-operator rule + +function foo(): void { + return; +} + +void foo(); // meaningless, foo() already returns void + +void undefined; // meaningless, undefined is already undefined + +async function bar() { + void (await somePromise); // meaningless if somePromise resolves to void +} \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/no-misused-spread/index.ts b/apps/oxlint/fixtures/tsgolint/no-misused-spread/index.ts new file mode 100644 index 0000000000000..336f9cd0c5c58 --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/no-misused-spread/index.ts @@ -0,0 +1,11 @@ +declare const promise: Promise; +const spreadPromise = { ...promise }; + +declare function getObject(): Record; +const getObjectSpread = { ...getObject }; + +declare const map: Map; +const mapSpread = { ...map }; + +declare const userName: string; +const characters = [...userName]; diff --git a/apps/oxlint/fixtures/tsgolint/no-mixed-enums/index.ts b/apps/oxlint/fixtures/tsgolint/no-mixed-enums/index.ts new file mode 100644 index 0000000000000..83480d502510a --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/no-mixed-enums/index.ts @@ -0,0 +1,13 @@ +// Examples of incorrect code for no-mixed-enums rule + +enum Status { + Open = 1, + Closed = 'closed', +} + +enum Direction { + Up = 'up', + Down = 2, + Left = 'left', + Right = 4, +} \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/no-redundant-type-constituents/index.ts b/apps/oxlint/fixtures/tsgolint/no-redundant-type-constituents/index.ts new file mode 100644 index 0000000000000..17d1eea47dd39 --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/no-redundant-type-constituents/index.ts @@ -0,0 +1,10 @@ +// Examples of incorrect code for no-redundant-type-constituents rule + +// unknown is redundant in unions +type T1 = string | unknown; + +// any is redundant in unions +type T2 = string | any; + +// never is redundant in unions +type T3 = string | never; \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/no-unnecessary-boolean-literal-compare/index.ts b/apps/oxlint/fixtures/tsgolint/no-unnecessary-boolean-literal-compare/index.ts new file mode 100644 index 0000000000000..0bf6cc1b919f2 --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/no-unnecessary-boolean-literal-compare/index.ts @@ -0,0 +1,11 @@ +// Examples of incorrect code for no-unnecessary-boolean-literal-compare rule + +declare const someCondition: boolean; + +if (someCondition === true) { + // ... +} + +if (someCondition === false) { + // ... +} \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/no-unnecessary-template-expression/index.ts b/apps/oxlint/fixtures/tsgolint/no-unnecessary-template-expression/index.ts new file mode 100644 index 0000000000000..157f6537dd2a9 --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/no-unnecessary-template-expression/index.ts @@ -0,0 +1,10 @@ +// Examples of incorrect code for no-unnecessary-template-expression rule + +const str1 = `Hello world`; + +const str2 = `42`; + +const str3 = `true`; + +// Template with only literal expressions +const str4 = `${'Hello'} ${'world'}`; \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/no-unnecessary-type-arguments/index.ts b/apps/oxlint/fixtures/tsgolint/no-unnecessary-type-arguments/index.ts new file mode 100644 index 0000000000000..5823f8cbb7045 --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/no-unnecessary-type-arguments/index.ts @@ -0,0 +1,12 @@ +// Examples of incorrect code for no-unnecessary-type-arguments rule + +function identity(arg: T): T { + return arg; +} + +// Unnecessary type argument - string is the default +const result = identity('hello'); + +interface Container { + value: T; +} \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/no-unnecessary-type-assertion/index.ts b/apps/oxlint/fixtures/tsgolint/no-unnecessary-type-assertion/index.ts new file mode 100644 index 0000000000000..826adad2e694d --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/no-unnecessary-type-assertion/index.ts @@ -0,0 +1,12 @@ +// Examples of incorrect code for no-unnecessary-type-assertion rule + +const str: string = 'hello'; +const redundant = str as string; // unnecessary, str is already string + +function getString(): string { + return 'hello'; +} +const result = getString() as string; // unnecessary, getString() already returns string + +const num = 42; +const alsoRedundant = num as 42; // unnecessary if TypeScript can infer literal type \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/no-unsafe-argument/index.ts b/apps/oxlint/fixtures/tsgolint/no-unsafe-argument/index.ts new file mode 100644 index 0000000000000..ab91796b9af43 --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/no-unsafe-argument/index.ts @@ -0,0 +1,12 @@ +// Examples of incorrect code for no-unsafe-argument rule + +declare const anyValue: any; + +function takesString(str: string): void { + console.log(str.length); +} + +takesString(anyValue); // unsafe + +declare function takesNumber(num: number): number; +const result = takesNumber(anyValue); // unsafe \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/no-unsafe-assignment/index.ts b/apps/oxlint/fixtures/tsgolint/no-unsafe-assignment/index.ts new file mode 100644 index 0000000000000..bd0aeb322cc32 --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/no-unsafe-assignment/index.ts @@ -0,0 +1,12 @@ +// Examples of incorrect code for no-unsafe-assignment rule + +declare const anyValue: any; + +const str: string = anyValue; // unsafe assignment + +let num: number; +num = anyValue; // unsafe assignment + +const obj = { + prop: anyValue as any, // unsafe assignment +}; \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/no-unsafe-call/index.ts b/apps/oxlint/fixtures/tsgolint/no-unsafe-call/index.ts new file mode 100644 index 0000000000000..700c4695f2c18 --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/no-unsafe-call/index.ts @@ -0,0 +1,12 @@ +// Examples of incorrect code for no-unsafe-call rule + +declare const anyValue: any; + +anyValue(); // unsafe call + +anyValue(1, 2, 3); // unsafe call + +const result = anyValue('hello'); // unsafe call + +// Chained unsafe calls +anyValue().then().catch(); // unsafe \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/no-unsafe-enum-comparison/index.ts b/apps/oxlint/fixtures/tsgolint/no-unsafe-enum-comparison/index.ts new file mode 100644 index 0000000000000..8886517588684 --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/no-unsafe-enum-comparison/index.ts @@ -0,0 +1,14 @@ +// Examples of incorrect code for no-unsafe-enum-comparison rule + +enum Status { + Open = 'open', + Closed = 'closed', +} + +enum Color { + Red = 'red', + Blue = 'blue', +} + +// Comparing different enums +const comparison = Status.Open === Color.Red; \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/no-unsafe-member-access/index.ts b/apps/oxlint/fixtures/tsgolint/no-unsafe-member-access/index.ts new file mode 100644 index 0000000000000..b44a4ac7501ca --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/no-unsafe-member-access/index.ts @@ -0,0 +1,11 @@ +// Examples of incorrect code for no-unsafe-member-access rule + +declare const anyValue: any; + +anyValue.foo; // unsafe member access + +anyValue.bar.baz; // unsafe nested member access + +anyValue['key']; // unsafe computed member access + +const result = anyValue.method(); // unsafe method access \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/no-unsafe-return/index.ts b/apps/oxlint/fixtures/tsgolint/no-unsafe-return/index.ts new file mode 100644 index 0000000000000..fff32c0f9f923 --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/no-unsafe-return/index.ts @@ -0,0 +1,13 @@ +// Examples of incorrect code for no-unsafe-return rule + +declare const anyValue: any; + +function getString(): string { + return anyValue; // unsafe return +} + +const getNumber = (): number => anyValue; // unsafe return + +function processData(): { name: string; age: number } { + return anyValue; // unsafe return +} \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/no-unsafe-type-assertion/index.ts b/apps/oxlint/fixtures/tsgolint/no-unsafe-type-assertion/index.ts new file mode 100644 index 0000000000000..292ba321b0fa5 --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/no-unsafe-type-assertion/index.ts @@ -0,0 +1,12 @@ +// Examples of incorrect code for no-unsafe-type-assertion rule + +declare const value: unknown; + +const str = value as any; // unsafe type assertion + +const obj = value as any as string; // double assertion through any + +function processValue(input: unknown) { + const processed = input as any; // unsafe + return processed.someProperty; +} \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/no-unsafe-unary-minus/index.ts b/apps/oxlint/fixtures/tsgolint/no-unsafe-unary-minus/index.ts new file mode 100644 index 0000000000000..bb4c89cff47da --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/no-unsafe-unary-minus/index.ts @@ -0,0 +1,13 @@ +// Examples of incorrect code for no-unsafe-unary-minus rule + +declare const value: any; +const result1 = -value; // unsafe on any + +declare const str: string; +const result2 = -str; // unsafe on string + +declare const bool: boolean; +const result3 = -bool; // unsafe on boolean + +declare const obj: object; +const result4 = -obj; // unsafe on object \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/non-nullable-type-assertion-style/index.ts b/apps/oxlint/fixtures/tsgolint/non-nullable-type-assertion-style/index.ts new file mode 100644 index 0000000000000..7de408660945c --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/non-nullable-type-assertion-style/index.ts @@ -0,0 +1,9 @@ +// Examples of incorrect code for non-nullable-type-assertion-style rule + +declare const value: string | null; + +// Type assertion when non-null assertion would be clearer +const result1 = value as string; + +declare const maybe: number | undefined; +const result2 = maybe as number; \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/only-throw-error/index.ts b/apps/oxlint/fixtures/tsgolint/only-throw-error/index.ts new file mode 100644 index 0000000000000..1f47a8f24fa4a --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/only-throw-error/index.ts @@ -0,0 +1,11 @@ +// Examples of incorrect code for only-throw-error rule + +throw 'error'; // throwing string + +throw 42; // throwing number + +throw true; // throwing boolean + +throw { message: 'error' }; // throwing plain object + +throw null; // throwing null \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/prefer-promise-reject-errors/index.ts b/apps/oxlint/fixtures/tsgolint/prefer-promise-reject-errors/index.ts new file mode 100644 index 0000000000000..0bb99b8c1497d --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/prefer-promise-reject-errors/index.ts @@ -0,0 +1,11 @@ +// Examples of incorrect code for prefer-promise-reject-errors rule + +Promise.reject('error'); // rejecting with string + +Promise.reject(42); // rejecting with number + +Promise.reject(true); // rejecting with boolean + +Promise.reject({ message: 'error' }); // rejecting with plain object + +Promise.reject(null); // rejecting with null \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/prefer-reduce-type-parameter/index.ts b/apps/oxlint/fixtures/tsgolint/prefer-reduce-type-parameter/index.ts new file mode 100644 index 0000000000000..e77da0b789017 --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/prefer-reduce-type-parameter/index.ts @@ -0,0 +1,12 @@ +// Examples of incorrect code for prefer-reduce-type-parameter rule + +const numbers = [1, 2, 3]; + +// Casting the result +const sum = numbers.reduce((acc, val) => acc + val, 0) as number; + +// Using type assertion on accumulator +const result = [1, 2, 3].reduce((acc: string[], curr) => { + acc.push(curr.toString()); + return acc; +}, [] as string[]); \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/prefer-return-this-type/index.ts b/apps/oxlint/fixtures/tsgolint/prefer-return-this-type/index.ts new file mode 100644 index 0000000000000..5823eff7cc532 --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/prefer-return-this-type/index.ts @@ -0,0 +1,14 @@ +// Examples of incorrect code for prefer-return-this-type rule + +class Builder { + private value: string = ''; + + setValue(value: string): Builder { // Should return 'this' + this.value = value; + return this; + } + + build(): string { + return this.value; + } +} \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/promise-function-async/index.ts b/apps/oxlint/fixtures/tsgolint/promise-function-async/index.ts new file mode 100644 index 0000000000000..f464367d7ba31 --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/promise-function-async/index.ts @@ -0,0 +1,13 @@ +// Examples of incorrect code for promise-function-async rule + +// Function returning Promise without async +function fetchData(): Promise { + return fetch('/api/data').then(res => res.text()); +} + +// Method returning Promise without async +class DataService { + getData(): Promise { + return fetch('/api/data').then(res => res.json()); + } +} \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/related-getter-setter-pairs/index.ts b/apps/oxlint/fixtures/tsgolint/related-getter-setter-pairs/index.ts new file mode 100644 index 0000000000000..6756fa89497c3 --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/related-getter-setter-pairs/index.ts @@ -0,0 +1,14 @@ +// Examples of incorrect code for related-getter-setter-pairs rule + +class Example { + private _value: number = 0; + + // Getter and setter with incompatible types + get value(): string { + return this._value.toString(); + } + + set value(val: number) { // Incompatible with getter + this._value = val; + } +} \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/require-array-sort-compare/index.ts b/apps/oxlint/fixtures/tsgolint/require-array-sort-compare/index.ts new file mode 100644 index 0000000000000..25bafd3f6babf --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/require-array-sort-compare/index.ts @@ -0,0 +1,9 @@ +// Examples of incorrect code for require-array-sort-compare rule + +const numbers = [3, 1, 4, 1, 5]; +numbers.sort(); // Lexicographic sort, not numeric + +const mixedArray = ['10', '2', '1']; +mixedArray.sort(); // Might be intended, but explicit compareFn is clearer + +[3, 1, 4].sort(); // Will sort as strings: ['1', '3', '4'] \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/require-await/index.ts b/apps/oxlint/fixtures/tsgolint/require-await/index.ts new file mode 100644 index 0000000000000..d342696721bfe --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/require-await/index.ts @@ -0,0 +1,11 @@ +// Examples of incorrect code for require-await rule + +// Async function without await +async function fetchData() { + return fetch('/api/data'); +} + +// Async arrow function without await +const processData = async () => { + return someData.map(x => x * 2); +}; \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/restrict-plus-operands/index.ts b/apps/oxlint/fixtures/tsgolint/restrict-plus-operands/index.ts new file mode 100644 index 0000000000000..8960e470652df --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/restrict-plus-operands/index.ts @@ -0,0 +1,2 @@ +let foo = 1n + 1; +let fn = (a: string, b: never) => a + b; diff --git a/apps/oxlint/fixtures/tsgolint/restrict-template-expressions/index.ts b/apps/oxlint/fixtures/tsgolint/restrict-template-expressions/index.ts new file mode 100644 index 0000000000000..e057e69e5fd69 --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/restrict-template-expressions/index.ts @@ -0,0 +1,18 @@ +// Examples of incorrect code for restrict-template-expressions rule + +declare const obj: object; +declare const sym: symbol; +declare const fn: () => void; +declare const arr: unknown[]; + +// Objects become "[object Object]" +const str1 = `Value: ${obj}`; + +// Symbols might not be what you expect +const str2 = `Symbol: ${sym}`; + +// Functions become their string representation +const str3 = `Function: ${fn}`; + +// Arrays of unknown might be unsafe +const str4 = `Array: ${arr}`; \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/return-await/index.ts b/apps/oxlint/fixtures/tsgolint/return-await/index.ts new file mode 100644 index 0000000000000..15df03418bc92 --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/return-await/index.ts @@ -0,0 +1,32 @@ +// Examples of incorrect code for return-await rule +// This rule requires consistent return await usage + +async function fetchUser(): Promise { + // Should be: return await getUser(); + return getUser(); // Missing await +} + +async function processData(): Promise { + try { + // Should be: return await fetchData(); + return fetchData(); // Missing await in try block + } catch (error) { + throw new Error('Failed to process'); + } +} + +// In try-catch, return await is recommended for proper stack traces +async function handleRequest(): Promise { + try { + return handleAsync(); // Should use await + } catch (error) { + console.error(error); + throw error; + } +} + +declare function getUser(): Promise; +declare function fetchData(): Promise; +declare function handleAsync(): Promise; +declare interface User { id: number; } +declare interface Response { data: any; } \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/switch-exhaustiveness-check/index.ts b/apps/oxlint/fixtures/tsgolint/switch-exhaustiveness-check/index.ts new file mode 100644 index 0000000000000..ec8f613b22c8e --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/switch-exhaustiveness-check/index.ts @@ -0,0 +1,13 @@ +// Examples of incorrect code for switch-exhaustiveness-check rule + +type Status = 'pending' | 'approved' | 'rejected'; + +function handleStatus(status: Status) { + switch (status) { + case 'pending': + return 'Waiting for approval'; + case 'approved': + return 'Request approved'; + // Missing 'rejected' case + } +} \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/unbound-method/index.ts b/apps/oxlint/fixtures/tsgolint/unbound-method/index.ts new file mode 100644 index 0000000000000..fa332dd94e6e1 --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/unbound-method/index.ts @@ -0,0 +1,31 @@ +// Examples of incorrect code for unbound-method rule + +class Calculator { + private value: number = 0; + + add(num: number): number { + this.value += num; + return this.value; + } + + getValue(): number { + return this.value; + } +} + +const calc = new Calculator(); + +// Unbound method - loses 'this' context +const addMethod = calc.add; +addMethod(5); // Error: 'this' is undefined + +// Array method callback loses context +const getValue = calc.getValue; +[1, 2, 3].map(getValue); // Error: each call loses 'this' + +// Unbound method in setTimeout +setTimeout(calc.add, 1000, 10); // Error: 'this' context lost + +// Class method destructuring +const { getValue: getVal } = calc; +getVal(); // Error: 'this' context lost \ No newline at end of file diff --git a/apps/oxlint/fixtures/tsgolint/use-unknown-in-catch-callback-variable/index.ts b/apps/oxlint/fixtures/tsgolint/use-unknown-in-catch-callback-variable/index.ts new file mode 100644 index 0000000000000..770255fce7a2d --- /dev/null +++ b/apps/oxlint/fixtures/tsgolint/use-unknown-in-catch-callback-variable/index.ts @@ -0,0 +1,35 @@ +// Examples of incorrect code for use-unknown-in-catch-callback-variable rule + +// Should use 'unknown' instead of 'any' +try { + riskyOperation(); +} catch (error: any) { // Should be: error: unknown + console.log(error.message); +} + +// Implicit 'any' in catch clause +try { + riskyOperation(); +} catch (error) { // Implicitly 'any', should be: error: unknown + handleError(error); +} + +// Promise catch with explicit any +promise.catch((error: any) => { // Should be: error: unknown + console.error(error.message); +}); + +// Callback with any error type +function handleAsync(callback: (error: any) => void) { // Should be: error: unknown + try { + performOperation(); + callback(null); + } catch (err) { + callback(err); + } +} + +declare function riskyOperation(): void; +declare function handleError(error: unknown): void; +declare const promise: Promise; +declare function performOperation(): void; \ No newline at end of file diff --git a/apps/oxlint/src/lint.rs b/apps/oxlint/src/lint.rs index fb3ac34ecb05d..6bd3b9483321e 100644 --- a/apps/oxlint/src/lint.rs +++ b/apps/oxlint/src/lint.rs @@ -1218,14 +1218,16 @@ mod test { #[test] #[cfg(not(target_endian = "big"))] fn test_tsgolint() { - let args = &["--type-aware"]; + // TODO: test with other rules as well once diagnostics are more stable + let args = &["--type-aware", "no-floating-promises"]; Tester::new().with_cwd("fixtures/tsgolint".into()).test_and_snapshot(args); } #[test] #[cfg(not(target_endian = "big"))] fn test_tsgolint_config() { - let args = &["--type-aware", "-c", "config-test.json"]; + // TODO: test with other rules as well once diagnostics are more stable + let args = &["--type-aware", "no-floating-promises", "-c", "config-test.json"]; Tester::new().with_cwd("fixtures/tsgolint".into()).test_and_snapshot(args); } } diff --git a/apps/oxlint/src/snapshots/_--ignore-path fixtures__linter__.customignore --no-ignore fixtures__linter__nan.js@oxlint.snap b/apps/oxlint/src/snapshots/_--ignore-path fixtures__linter__.customignore --no-ignore fixtures__linter__nan.js@oxlint.snap index 14d5edc37b894..6383673e149f2 100644 --- a/apps/oxlint/src/snapshots/_--ignore-path fixtures__linter__.customignore --no-ignore fixtures__linter__nan.js@oxlint.snap +++ b/apps/oxlint/src/snapshots/_--ignore-path fixtures__linter__.customignore --no-ignore fixtures__linter__nan.js@oxlint.snap @@ -14,7 +14,7 @@ working directory: help: Use the isNaN function to compare with NaN. Found 1 warning and 0 errors. -Finished in ms on 1 file with 88 rules using 1 threads. +Finished in ms on 1 file with 103 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/_--ignore-pattern _____.js --ignore-pattern _____.vue fixtures__linter@oxlint.snap b/apps/oxlint/src/snapshots/_--ignore-pattern _____.js --ignore-pattern _____.vue fixtures__linter@oxlint.snap index 4df9f6236759d..7f4957aa760e0 100644 --- a/apps/oxlint/src/snapshots/_--ignore-pattern _____.js --ignore-pattern _____.vue fixtures__linter@oxlint.snap +++ b/apps/oxlint/src/snapshots/_--ignore-pattern _____.js --ignore-pattern _____.vue fixtures__linter@oxlint.snap @@ -6,7 +6,7 @@ arguments: --ignore-pattern **/*.js --ignore-pattern **/*.vue fixtures/linter working directory: ---------- Found 0 warnings and 0 errors. -Finished in ms on 0 files with 88 rules using 1 threads. +Finished in ms on 0 files with 103 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/_--import-plugin -A all -D no-cycle fixtures__flow__@oxlint.snap b/apps/oxlint/src/snapshots/_--import-plugin -A all -D no-cycle fixtures__flow__@oxlint.snap index 6b279aaf7880d..fc9f70b42dce4 100644 --- a/apps/oxlint/src/snapshots/_--import-plugin -A all -D no-cycle fixtures__flow__@oxlint.snap +++ b/apps/oxlint/src/snapshots/_--import-plugin -A all -D no-cycle fixtures__flow__@oxlint.snap @@ -6,7 +6,7 @@ arguments: --import-plugin -A all -D no-cycle fixtures/flow/ working directory: ---------- Found 0 warnings and 0 errors. -Finished in ms on 2 files with 90 rules using 1 threads. +Finished in ms on 2 files with 105 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/_--import-plugin fixtures__flow__index.mjs@oxlint.snap b/apps/oxlint/src/snapshots/_--import-plugin fixtures__flow__index.mjs@oxlint.snap index cfceefea6e34f..70d4831301d21 100644 --- a/apps/oxlint/src/snapshots/_--import-plugin fixtures__flow__index.mjs@oxlint.snap +++ b/apps/oxlint/src/snapshots/_--import-plugin fixtures__flow__index.mjs@oxlint.snap @@ -6,7 +6,7 @@ arguments: --import-plugin fixtures/flow/index.mjs working directory: ---------- Found 0 warnings and 0 errors. -Finished in ms on 1 file with 90 rules using 1 threads. +Finished in ms on 1 file with 105 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/_--vitest-plugin -c fixtures__eslintrc_vitest_replace__eslintrc.json fixtures__eslintrc_vitest_replace__foo.test.js@oxlint.snap b/apps/oxlint/src/snapshots/_--vitest-plugin -c fixtures__eslintrc_vitest_replace__eslintrc.json fixtures__eslintrc_vitest_replace__foo.test.js@oxlint.snap index c4d380529edec..506d6f5983c6e 100644 --- a/apps/oxlint/src/snapshots/_--vitest-plugin -c fixtures__eslintrc_vitest_replace__eslintrc.json fixtures__eslintrc_vitest_replace__foo.test.js@oxlint.snap +++ b/apps/oxlint/src/snapshots/_--vitest-plugin -c fixtures__eslintrc_vitest_replace__eslintrc.json fixtures__eslintrc_vitest_replace__foo.test.js@oxlint.snap @@ -23,7 +23,7 @@ working directory: help: Remove the appending `.skip` Found 1 warning and 1 error. -Finished in ms on 1 file with 100 rules using 1 threads. +Finished in ms on 1 file with 115 rules using 1 threads. ---------- CLI result: LintFoundErrors ---------- diff --git a/apps/oxlint/src/snapshots/_-D correctness fixtures__linter__debugger.js@oxlint.snap b/apps/oxlint/src/snapshots/_-D correctness fixtures__linter__debugger.js@oxlint.snap index e8a7439a56489..a95ce9902169d 100644 --- a/apps/oxlint/src/snapshots/_-D correctness fixtures__linter__debugger.js@oxlint.snap +++ b/apps/oxlint/src/snapshots/_-D correctness fixtures__linter__debugger.js@oxlint.snap @@ -14,7 +14,7 @@ working directory: help: Remove the debugger statement Found 0 warnings and 1 error. -Finished in ms on 1 file with 88 rules using 1 threads. +Finished in ms on 1 file with 103 rules using 1 threads. ---------- CLI result: LintFoundErrors ---------- diff --git a/apps/oxlint/src/snapshots/_-W correctness -A no-debugger fixtures__linter__debugger.js@oxlint.snap b/apps/oxlint/src/snapshots/_-W correctness -A no-debugger fixtures__linter__debugger.js@oxlint.snap index 7d865615b1c26..bea696bba4f31 100644 --- a/apps/oxlint/src/snapshots/_-W correctness -A no-debugger fixtures__linter__debugger.js@oxlint.snap +++ b/apps/oxlint/src/snapshots/_-W correctness -A no-debugger fixtures__linter__debugger.js@oxlint.snap @@ -6,7 +6,7 @@ arguments: -W correctness -A no-debugger fixtures/linter/debugger.js working directory: ---------- Found 0 warnings and 0 errors. -Finished in ms on 1 file with 87 rules using 1 threads. +Finished in ms on 1 file with 102 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/_-W no-undef -c fixtures__eslintrc_env__eslintrc_no_env.json fixtures__eslintrc_env__test.js@oxlint.snap b/apps/oxlint/src/snapshots/_-W no-undef -c fixtures__eslintrc_env__eslintrc_no_env.json fixtures__eslintrc_env__test.js@oxlint.snap index 0d3edb0f3f202..16b4764f9bc97 100644 --- a/apps/oxlint/src/snapshots/_-W no-undef -c fixtures__eslintrc_env__eslintrc_no_env.json fixtures__eslintrc_env__test.js@oxlint.snap +++ b/apps/oxlint/src/snapshots/_-W no-undef -c fixtures__eslintrc_env__eslintrc_no_env.json fixtures__eslintrc_env__test.js@oxlint.snap @@ -13,7 +13,7 @@ working directory: `---- Found 1 warning and 0 errors. -Finished in ms on 1 file with 89 rules using 1 threads. +Finished in ms on 1 file with 104 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/_-W no-undef -c fixtures__no_undef__eslintrc.json fixtures__no_undef__test.js@oxlint.snap b/apps/oxlint/src/snapshots/_-W no-undef -c fixtures__no_undef__eslintrc.json fixtures__no_undef__test.js@oxlint.snap index d8e1263173caa..ec7e4372f580f 100644 --- a/apps/oxlint/src/snapshots/_-W no-undef -c fixtures__no_undef__eslintrc.json fixtures__no_undef__test.js@oxlint.snap +++ b/apps/oxlint/src/snapshots/_-W no-undef -c fixtures__no_undef__eslintrc.json fixtures__no_undef__test.js@oxlint.snap @@ -13,7 +13,7 @@ working directory: `---- Found 1 warning and 0 errors. -Finished in ms on 1 file with 89 rules using 1 threads. +Finished in ms on 1 file with 104 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/_-c fixtures__config_ignore_patterns__ignore_extension__eslintrc.json fixtures__config_ignore_patterns__ignore_extension@oxlint.snap b/apps/oxlint/src/snapshots/_-c fixtures__config_ignore_patterns__ignore_extension__eslintrc.json fixtures__config_ignore_patterns__ignore_extension@oxlint.snap index 94ff47a62435e..d63cfc5d545a4 100644 --- a/apps/oxlint/src/snapshots/_-c fixtures__config_ignore_patterns__ignore_extension__eslintrc.json fixtures__config_ignore_patterns__ignore_extension@oxlint.snap +++ b/apps/oxlint/src/snapshots/_-c fixtures__config_ignore_patterns__ignore_extension__eslintrc.json fixtures__config_ignore_patterns__ignore_extension@oxlint.snap @@ -12,7 +12,7 @@ working directory: help: Delete this file or add some code to it. Found 1 warning and 0 errors. -Finished in ms on 1 file with 88 rules using 1 threads. +Finished in ms on 1 file with 103 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/_-c fixtures__eslintrc_env__eslintrc_env_browser.json fixtures__eslintrc_env__test.js@oxlint.snap b/apps/oxlint/src/snapshots/_-c fixtures__eslintrc_env__eslintrc_env_browser.json fixtures__eslintrc_env__test.js@oxlint.snap index 25501e80c4580..7533893b7da42 100644 --- a/apps/oxlint/src/snapshots/_-c fixtures__eslintrc_env__eslintrc_env_browser.json fixtures__eslintrc_env__test.js@oxlint.snap +++ b/apps/oxlint/src/snapshots/_-c fixtures__eslintrc_env__eslintrc_env_browser.json fixtures__eslintrc_env__test.js@oxlint.snap @@ -6,7 +6,7 @@ arguments: -c fixtures/eslintrc_env/eslintrc_env_browser.json fixtures/eslintrc_ working directory: ---------- Found 0 warnings and 0 errors. -Finished in ms on 1 file with 89 rules using 1 threads. +Finished in ms on 1 file with 104 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/_-c fixtures__eslintrc_off__eslintrc.json fixtures__eslintrc_off__test.js@oxlint.snap b/apps/oxlint/src/snapshots/_-c fixtures__eslintrc_off__eslintrc.json fixtures__eslintrc_off__test.js@oxlint.snap index f4589994fed67..30e10bb2bc6cf 100644 --- a/apps/oxlint/src/snapshots/_-c fixtures__eslintrc_off__eslintrc.json fixtures__eslintrc_off__test.js@oxlint.snap +++ b/apps/oxlint/src/snapshots/_-c fixtures__eslintrc_off__eslintrc.json fixtures__eslintrc_off__test.js@oxlint.snap @@ -12,7 +12,7 @@ working directory: help: Delete this file or add some code to it. Found 1 warning and 0 errors. -Finished in ms on 1 file with 88 rules using 1 threads. +Finished in ms on 1 file with 103 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/_-c fixtures__eslintrc_vitest_replace__eslintrc.json fixtures__eslintrc_vitest_replace__foo.test.js@oxlint.snap b/apps/oxlint/src/snapshots/_-c fixtures__eslintrc_vitest_replace__eslintrc.json fixtures__eslintrc_vitest_replace__foo.test.js@oxlint.snap index fa6cb18220a4b..2b6f666a27bdc 100644 --- a/apps/oxlint/src/snapshots/_-c fixtures__eslintrc_vitest_replace__eslintrc.json fixtures__eslintrc_vitest_replace__foo.test.js@oxlint.snap +++ b/apps/oxlint/src/snapshots/_-c fixtures__eslintrc_vitest_replace__eslintrc.json fixtures__eslintrc_vitest_replace__foo.test.js@oxlint.snap @@ -6,7 +6,7 @@ arguments: -c fixtures/eslintrc_vitest_replace/eslintrc.json fixtures/eslintrc_v working directory: ---------- Found 0 warnings and 0 errors. -Finished in ms on 1 file with 88 rules using 1 threads. +Finished in ms on 1 file with 103 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/_-c fixtures__linter__eslintrc.json fixtures__linter__debugger.js@oxlint.snap b/apps/oxlint/src/snapshots/_-c fixtures__linter__eslintrc.json fixtures__linter__debugger.js@oxlint.snap index afa75f25536d0..93a2b6b92b70e 100644 --- a/apps/oxlint/src/snapshots/_-c fixtures__linter__eslintrc.json fixtures__linter__debugger.js@oxlint.snap +++ b/apps/oxlint/src/snapshots/_-c fixtures__linter__eslintrc.json fixtures__linter__debugger.js@oxlint.snap @@ -14,7 +14,7 @@ working directory: help: Remove the debugger statement Found 0 warnings and 1 error. -Finished in ms on 1 file with 88 rules using 1 threads. +Finished in ms on 1 file with 103 rules using 1 threads. ---------- CLI result: LintFoundErrors ---------- diff --git a/apps/oxlint/src/snapshots/_-c fixtures__no_console_off__eslintrc.json fixtures__no_console_off__test.js@oxlint.snap b/apps/oxlint/src/snapshots/_-c fixtures__no_console_off__eslintrc.json fixtures__no_console_off__test.js@oxlint.snap index ec9911f1422e1..ffa29bfda4399 100644 --- a/apps/oxlint/src/snapshots/_-c fixtures__no_console_off__eslintrc.json fixtures__no_console_off__test.js@oxlint.snap +++ b/apps/oxlint/src/snapshots/_-c fixtures__no_console_off__eslintrc.json fixtures__no_console_off__test.js@oxlint.snap @@ -6,7 +6,7 @@ arguments: -c fixtures/no_console_off/eslintrc.json fixtures/no_console_off/test working directory: ---------- Found 0 warnings and 0 errors. -Finished in ms on 1 file with 88 rules using 1 threads. +Finished in ms on 1 file with 103 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/_-c fixtures__no_empty_allow_empty_catch__eslintrc.json -W no-empty fixtures__no_empty_allow_empty_catch__test.js@oxlint.snap b/apps/oxlint/src/snapshots/_-c fixtures__no_empty_allow_empty_catch__eslintrc.json -W no-empty fixtures__no_empty_allow_empty_catch__test.js@oxlint.snap index 44e6c594b0c26..03bfb7584baf3 100644 --- a/apps/oxlint/src/snapshots/_-c fixtures__no_empty_allow_empty_catch__eslintrc.json -W no-empty fixtures__no_empty_allow_empty_catch__test.js@oxlint.snap +++ b/apps/oxlint/src/snapshots/_-c fixtures__no_empty_allow_empty_catch__eslintrc.json -W no-empty fixtures__no_empty_allow_empty_catch__test.js@oxlint.snap @@ -6,7 +6,7 @@ arguments: -c fixtures/no_empty_allow_empty_catch/eslintrc.json -W no-empty fixt working directory: ---------- Found 0 warnings and 0 errors. -Finished in ms on 1 file with 89 rules using 1 threads. +Finished in ms on 1 file with 104 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/_-c fixtures__no_empty_disallow_empty_catch__eslintrc.json -W no-empty fixtures__no_empty_disallow_empty_catch__test.js@oxlint.snap b/apps/oxlint/src/snapshots/_-c fixtures__no_empty_disallow_empty_catch__eslintrc.json -W no-empty fixtures__no_empty_disallow_empty_catch__test.js@oxlint.snap index aee8e702efcca..10e60d3af035f 100644 --- a/apps/oxlint/src/snapshots/_-c fixtures__no_empty_disallow_empty_catch__eslintrc.json -W no-empty fixtures__no_empty_disallow_empty_catch__test.js@oxlint.snap +++ b/apps/oxlint/src/snapshots/_-c fixtures__no_empty_disallow_empty_catch__eslintrc.json -W no-empty fixtures__no_empty_disallow_empty_catch__test.js@oxlint.snap @@ -14,7 +14,7 @@ working directory: help: Remove this block or add a comment inside it Found 1 warning and 0 errors. -Finished in ms on 1 file with 89 rules using 1 threads. +Finished in ms on 1 file with 104 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/_-c fixtures__overrides__.oxlintrc.json fixtures__overrides__test.js -c fixtures__overrides__.oxlintrc.json fixtures__overrides__test.ts -c fixtures__overrides__.oxlintrc.json fixtures__overrides__other.jsx@oxlint.snap b/apps/oxlint/src/snapshots/_-c fixtures__overrides__.oxlintrc.json fixtures__overrides__test.js -c fixtures__overrides__.oxlintrc.json fixtures__overrides__test.ts -c fixtures__overrides__.oxlintrc.json fixtures__overrides__other.jsx@oxlint.snap index db17dd6cea37a..8ce84946c441d 100644 --- a/apps/oxlint/src/snapshots/_-c fixtures__overrides__.oxlintrc.json fixtures__overrides__test.js -c fixtures__overrides__.oxlintrc.json fixtures__overrides__test.ts -c fixtures__overrides__.oxlintrc.json fixtures__overrides__other.jsx@oxlint.snap +++ b/apps/oxlint/src/snapshots/_-c fixtures__overrides__.oxlintrc.json fixtures__overrides__test.js -c fixtures__overrides__.oxlintrc.json fixtures__overrides__test.ts -c fixtures__overrides__.oxlintrc.json fixtures__overrides__other.jsx@oxlint.snap @@ -15,7 +15,7 @@ working directory: help: Replace var with let or const Found 0 warnings and 1 error. -Finished in ms on 1 file with 90 rules using 1 threads. +Finished in ms on 1 file with 105 rules using 1 threads. ---------- CLI result: LintFoundErrors ---------- @@ -42,7 +42,7 @@ working directory: help: Delete this console statement. Found 1 warning and 1 error. -Finished in ms on 1 file with 90 rules using 1 threads. +Finished in ms on 1 file with 105 rules using 1 threads. ---------- CLI result: LintFoundErrors ---------- @@ -61,7 +61,7 @@ working directory: help: Replace var with let or const Found 0 warnings and 1 error. -Finished in ms on 1 file with 90 rules using 1 threads. +Finished in ms on 1 file with 105 rules using 1 threads. ---------- CLI result: LintFoundErrors ---------- diff --git a/apps/oxlint/src/snapshots/_-c fixtures__overrides__directories-config.json fixtures__overrides@oxlint.snap b/apps/oxlint/src/snapshots/_-c fixtures__overrides__directories-config.json fixtures__overrides@oxlint.snap index f114ad02fc06c..5d14a095539f8 100644 --- a/apps/oxlint/src/snapshots/_-c fixtures__overrides__directories-config.json fixtures__overrides@oxlint.snap +++ b/apps/oxlint/src/snapshots/_-c fixtures__overrides__directories-config.json fixtures__overrides@oxlint.snap @@ -35,7 +35,7 @@ working directory: help: Remove the debugger statement Found 2 warnings and 2 errors. -Finished in ms on 7 files with 87 rules using 1 threads. +Finished in ms on 7 files with 102 rules using 1 threads. ---------- CLI result: LintFoundErrors ---------- diff --git a/apps/oxlint/src/snapshots/_-c fixtures__typescript_eslint__eslintrc.json fixtures__typescript_eslint__test.ts@oxlint.snap b/apps/oxlint/src/snapshots/_-c fixtures__typescript_eslint__eslintrc.json fixtures__typescript_eslint__test.ts@oxlint.snap index eab9dad447078..871e5c37491fa 100644 --- a/apps/oxlint/src/snapshots/_-c fixtures__typescript_eslint__eslintrc.json fixtures__typescript_eslint__test.ts@oxlint.snap +++ b/apps/oxlint/src/snapshots/_-c fixtures__typescript_eslint__eslintrc.json fixtures__typescript_eslint__test.ts@oxlint.snap @@ -31,7 +31,7 @@ working directory: `---- Found 2 warnings and 1 error. -Finished in ms on 1 file with 63 rules using 1 threads. +Finished in ms on 1 file with 78 rules using 1 threads. ---------- CLI result: LintFoundErrors ---------- diff --git a/apps/oxlint/src/snapshots/_fixtures__astro__debugger.astro@oxlint.snap b/apps/oxlint/src/snapshots/_fixtures__astro__debugger.astro@oxlint.snap index 4e6ea777724c3..aa6b174298f16 100644 --- a/apps/oxlint/src/snapshots/_fixtures__astro__debugger.astro@oxlint.snap +++ b/apps/oxlint/src/snapshots/_fixtures__astro__debugger.astro@oxlint.snap @@ -43,7 +43,7 @@ working directory: help: Remove the debugger statement Found 4 warnings and 0 errors. -Finished in ms on 1 file with 88 rules using 1 threads. +Finished in ms on 1 file with 103 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/_fixtures__linter@oxlint.snap b/apps/oxlint/src/snapshots/_fixtures__linter@oxlint.snap index c4f6832be41cb..755d81d911074 100644 --- a/apps/oxlint/src/snapshots/_fixtures__linter@oxlint.snap +++ b/apps/oxlint/src/snapshots/_fixtures__linter@oxlint.snap @@ -29,7 +29,7 @@ working directory: help: Use the isNaN function to compare with NaN. Found 3 warnings and 0 errors. -Finished in ms on 3 files with 88 rules using 1 threads. +Finished in ms on 3 files with 103 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/_fixtures__linter__debugger.js fixtures__linter__nan.js@oxlint.snap b/apps/oxlint/src/snapshots/_fixtures__linter__debugger.js fixtures__linter__nan.js@oxlint.snap index 7abab6af6a633..731e3fbfe2b50 100644 --- a/apps/oxlint/src/snapshots/_fixtures__linter__debugger.js fixtures__linter__nan.js@oxlint.snap +++ b/apps/oxlint/src/snapshots/_fixtures__linter__debugger.js fixtures__linter__nan.js@oxlint.snap @@ -21,7 +21,7 @@ working directory: help: Use the isNaN function to compare with NaN. Found 2 warnings and 0 errors. -Finished in ms on 2 files with 88 rules using 1 threads. +Finished in ms on 2 files with 103 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/_fixtures__linter__debugger.js@oxlint.snap b/apps/oxlint/src/snapshots/_fixtures__linter__debugger.js@oxlint.snap index dc5b0018fb3fb..5a6655a054e7f 100644 --- a/apps/oxlint/src/snapshots/_fixtures__linter__debugger.js@oxlint.snap +++ b/apps/oxlint/src/snapshots/_fixtures__linter__debugger.js@oxlint.snap @@ -14,7 +14,7 @@ working directory: help: Remove the debugger statement Found 1 warning and 0 errors. -Finished in ms on 1 file with 88 rules using 1 threads. +Finished in ms on 1 file with 103 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/_fixtures__linter__js_as_jsx.js@oxlint.snap b/apps/oxlint/src/snapshots/_fixtures__linter__js_as_jsx.js@oxlint.snap index 6f10c0e933022..7c6b3bfcd0687 100644 --- a/apps/oxlint/src/snapshots/_fixtures__linter__js_as_jsx.js@oxlint.snap +++ b/apps/oxlint/src/snapshots/_fixtures__linter__js_as_jsx.js@oxlint.snap @@ -15,7 +15,7 @@ working directory: help: Remove the debugger statement Found 1 warning and 0 errors. -Finished in ms on 1 file with 88 rules using 1 threads. +Finished in ms on 1 file with 103 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/_fixtures__svelte__debugger.svelte@oxlint.snap b/apps/oxlint/src/snapshots/_fixtures__svelte__debugger.svelte@oxlint.snap index 10d430a9d26ee..4c52737590cb0 100644 --- a/apps/oxlint/src/snapshots/_fixtures__svelte__debugger.svelte@oxlint.snap +++ b/apps/oxlint/src/snapshots/_fixtures__svelte__debugger.svelte@oxlint.snap @@ -34,7 +34,7 @@ working directory: help: Variable declared without assignment. Either assign a value or remove the declaration. Found 3 warnings and 0 errors. -Finished in ms on 1 file with 88 rules using 1 threads. +Finished in ms on 1 file with 103 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/_fixtures__vue__debugger.vue@oxlint.snap b/apps/oxlint/src/snapshots/_fixtures__vue__debugger.vue@oxlint.snap index 923455acb9d95..c828a7e4c2ac5 100644 --- a/apps/oxlint/src/snapshots/_fixtures__vue__debugger.vue@oxlint.snap +++ b/apps/oxlint/src/snapshots/_fixtures__vue__debugger.vue@oxlint.snap @@ -25,7 +25,7 @@ working directory: help: Remove the debugger statement Found 2 warnings and 0 errors. -Finished in ms on 1 file with 88 rules using 1 threads. +Finished in ms on 1 file with 103 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/_fixtures__vue__empty.vue@oxlint.snap b/apps/oxlint/src/snapshots/_fixtures__vue__empty.vue@oxlint.snap index 9bc332a438637..0187cc3dd0fc5 100644 --- a/apps/oxlint/src/snapshots/_fixtures__vue__empty.vue@oxlint.snap +++ b/apps/oxlint/src/snapshots/_fixtures__vue__empty.vue@oxlint.snap @@ -6,7 +6,7 @@ arguments: fixtures/vue/empty.vue working directory: ---------- Found 0 warnings and 0 errors. -Finished in ms on 1 file with 88 rules using 1 threads. +Finished in ms on 1 file with 103 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/_foo.asdf@oxlint.snap b/apps/oxlint/src/snapshots/_foo.asdf@oxlint.snap index b318daf82400b..fd55cc27e576d 100644 --- a/apps/oxlint/src/snapshots/_foo.asdf@oxlint.snap +++ b/apps/oxlint/src/snapshots/_foo.asdf@oxlint.snap @@ -6,7 +6,7 @@ arguments: foo.asdf working directory: ---------- Found 0 warnings and 0 errors. -Finished in ms on 0 files with 88 rules using 1 threads. +Finished in ms on 0 files with 103 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/fixtures__config_ignore_patterns__ignore_directory_-c eslintrc.json@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__config_ignore_patterns__ignore_directory_-c eslintrc.json@oxlint.snap index e8714e8681f0d..475154beadd24 100644 --- a/apps/oxlint/src/snapshots/fixtures__config_ignore_patterns__ignore_directory_-c eslintrc.json@oxlint.snap +++ b/apps/oxlint/src/snapshots/fixtures__config_ignore_patterns__ignore_directory_-c eslintrc.json@oxlint.snap @@ -14,7 +14,7 @@ working directory: fixtures/config_ignore_patterns/ignore_directory help: Delete this file or add some code to it. Found 1 warning and 0 errors. -Finished in ms on 1 file with 88 rules using 1 threads. +Finished in ms on 1 file with 103 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/fixtures__config_ignore_patterns__with_oxlintrc_-c .__test__eslintrc.json --ignore-pattern _.ts .@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__config_ignore_patterns__with_oxlintrc_-c .__test__eslintrc.json --ignore-pattern _.ts .@oxlint.snap index 8234789592793..2a3764fb5379a 100644 --- a/apps/oxlint/src/snapshots/fixtures__config_ignore_patterns__with_oxlintrc_-c .__test__eslintrc.json --ignore-pattern _.ts .@oxlint.snap +++ b/apps/oxlint/src/snapshots/fixtures__config_ignore_patterns__with_oxlintrc_-c .__test__eslintrc.json --ignore-pattern _.ts .@oxlint.snap @@ -12,7 +12,7 @@ working directory: fixtures/config_ignore_patterns/with_oxlintrc help: Delete this file or add some code to it. Found 1 warning and 0 errors. -Finished in ms on 1 file with 88 rules using 1 threads. +Finished in ms on 1 file with 103 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/fixtures__extends_config_--config extends_rules_config.json console.js@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__extends_config_--config extends_rules_config.json console.js@oxlint.snap index 2c5078e8ae2cf..bd68e13c9c19e 100644 --- a/apps/oxlint/src/snapshots/fixtures__extends_config_--config extends_rules_config.json console.js@oxlint.snap +++ b/apps/oxlint/src/snapshots/fixtures__extends_config_--config extends_rules_config.json console.js@oxlint.snap @@ -14,7 +14,7 @@ working directory: fixtures/extends_config help: Delete this console statement. Found 0 warnings and 1 error. -Finished in ms on 1 file with 89 rules using 1 threads. +Finished in ms on 1 file with 104 rules using 1 threads. ---------- CLI result: LintFoundErrors ---------- diff --git a/apps/oxlint/src/snapshots/fixtures__extends_config_--config relative_paths__extends_extends_config.json console.js@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__extends_config_--config relative_paths__extends_extends_config.json console.js@oxlint.snap index 2560d77f56c60..3bdb79146e39f 100644 --- a/apps/oxlint/src/snapshots/fixtures__extends_config_--config relative_paths__extends_extends_config.json console.js@oxlint.snap +++ b/apps/oxlint/src/snapshots/fixtures__extends_config_--config relative_paths__extends_extends_config.json console.js@oxlint.snap @@ -14,7 +14,7 @@ working directory: fixtures/extends_config help: Delete this console statement. Found 0 warnings and 1 error. -Finished in ms on 1 file with 89 rules using 1 threads. +Finished in ms on 1 file with 104 rules using 1 threads. ---------- CLI result: LintFoundErrors ---------- diff --git a/apps/oxlint/src/snapshots/fixtures__extends_config_--disable-nested-config@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__extends_config_--disable-nested-config@oxlint.snap index 5f3ad63228d56..4417bb56980fd 100644 --- a/apps/oxlint/src/snapshots/fixtures__extends_config_--disable-nested-config@oxlint.snap +++ b/apps/oxlint/src/snapshots/fixtures__extends_config_--disable-nested-config@oxlint.snap @@ -31,7 +31,7 @@ working directory: fixtures/extends_config help: Remove the debugger statement Found 3 warnings and 0 errors. -Finished in ms on 4 files with 88 rules using 1 threads. +Finished in ms on 4 files with 103 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/fixtures__ignore_file_current_dir_ .@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__ignore_file_current_dir_ .@oxlint.snap index 29cdf97328fc1..d88052aa1e805 100644 --- a/apps/oxlint/src/snapshots/fixtures__ignore_file_current_dir_ .@oxlint.snap +++ b/apps/oxlint/src/snapshots/fixtures__ignore_file_current_dir_ .@oxlint.snap @@ -6,7 +6,7 @@ arguments: working directory: fixtures/ignore_file_current_dir ---------- Found 0 warnings and 0 errors. -Finished in ms on 0 files with 88 rules using 1 threads. +Finished in ms on 0 files with 103 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- @@ -16,7 +16,7 @@ arguments: . working directory: fixtures/ignore_file_current_dir ---------- Found 0 warnings and 0 errors. -Finished in ms on 0 files with 88 rules using 1 threads. +Finished in ms on 0 files with 103 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/fixtures__import-cycle_--import-plugin -D import__no-cycle@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__import-cycle_--import-plugin -D import__no-cycle@oxlint.snap index 0124f24f7b2c9..85b521fc3c5db 100644 --- a/apps/oxlint/src/snapshots/fixtures__import-cycle_--import-plugin -D import__no-cycle@oxlint.snap +++ b/apps/oxlint/src/snapshots/fixtures__import-cycle_--import-plugin -D import__no-cycle@oxlint.snap @@ -27,7 +27,7 @@ working directory: fixtures/import-cycle -> ./b - fixtures/import-cycle/b.ts Found 0 warnings and 2 errors. -Finished in ms on 2 files with 91 rules using 1 threads. +Finished in ms on 2 files with 106 rules using 1 threads. ---------- CLI result: LintFoundErrors ---------- diff --git a/apps/oxlint/src/snapshots/fixtures__issue_10394_-c .oxlintrc.json@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__issue_10394_-c .oxlintrc.json@oxlint.snap index de60c8e2330d0..99924b8e584b7 100644 --- a/apps/oxlint/src/snapshots/fixtures__issue_10394_-c .oxlintrc.json@oxlint.snap +++ b/apps/oxlint/src/snapshots/fixtures__issue_10394_-c .oxlintrc.json@oxlint.snap @@ -15,7 +15,7 @@ working directory: fixtures/issue_10394 help: "Write a meaningful title for your test" Found 1 warning and 0 errors. -Finished in ms on 1 file with 88 rules using 1 threads. +Finished in ms on 1 file with 103 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/fixtures__issue_11054_-c .oxlintrc.json@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__issue_11054_-c .oxlintrc.json@oxlint.snap index 021cd19d338c5..f90bd178a5ffa 100644 --- a/apps/oxlint/src/snapshots/fixtures__issue_11054_-c .oxlintrc.json@oxlint.snap +++ b/apps/oxlint/src/snapshots/fixtures__issue_11054_-c .oxlintrc.json@oxlint.snap @@ -6,7 +6,7 @@ arguments: -c .oxlintrc.json working directory: fixtures/issue_11054 ---------- Found 0 warnings and 0 errors. -Finished in ms on 1 file with 88 rules using 1 threads. +Finished in ms on 1 file with 103 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/fixtures__issue_11644_-c .oxlintrc.json@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__issue_11644_-c .oxlintrc.json@oxlint.snap index 9fa98d0346d17..25cfb362f0196 100644 --- a/apps/oxlint/src/snapshots/fixtures__issue_11644_-c .oxlintrc.json@oxlint.snap +++ b/apps/oxlint/src/snapshots/fixtures__issue_11644_-c .oxlintrc.json@oxlint.snap @@ -6,7 +6,7 @@ arguments: -c .oxlintrc.json working directory: fixtures/issue_11644 ---------- Found 0 warnings and 0 errors. -Finished in ms on 1 file with 160 rules using 1 threads. +Finished in ms on 1 file with 175 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/fixtures__linter_debugger.js@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__linter_debugger.js@oxlint.snap index 9d6d855ef3212..e514d0eabc35a 100644 --- a/apps/oxlint/src/snapshots/fixtures__linter_debugger.js@oxlint.snap +++ b/apps/oxlint/src/snapshots/fixtures__linter_debugger.js@oxlint.snap @@ -14,7 +14,7 @@ working directory: fixtures/linter help: Remove the debugger statement Found 1 warning and 0 errors. -Finished in ms on 1 file with 88 rules using 1 threads. +Finished in ms on 1 file with 103 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/fixtures__overrides_env_globals_-c .oxlintrc.json .@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__overrides_env_globals_-c .oxlintrc.json .@oxlint.snap index efad408ad3993..9550f157b60a4 100644 --- a/apps/oxlint/src/snapshots/fixtures__overrides_env_globals_-c .oxlintrc.json .@oxlint.snap +++ b/apps/oxlint/src/snapshots/fixtures__overrides_env_globals_-c .oxlintrc.json .@oxlint.snap @@ -51,7 +51,7 @@ working directory: fixtures/overrides_env_globals `---- Found 5 warnings and 0 errors. -Finished in ms on 3 files with 88 rules using 1 threads. +Finished in ms on 3 files with 103 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/fixtures__overrides_with_plugin_-c .oxlintrc.json@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__overrides_with_plugin_-c .oxlintrc.json@oxlint.snap index cfba320384f06..c46975ef6d7bd 100644 --- a/apps/oxlint/src/snapshots/fixtures__overrides_with_plugin_-c .oxlintrc.json@oxlint.snap +++ b/apps/oxlint/src/snapshots/fixtures__overrides_with_plugin_-c .oxlintrc.json@oxlint.snap @@ -42,7 +42,7 @@ working directory: fixtures/overrides_with_plugin help: Consider removing this declaration. Found 2 warnings and 2 errors. -Finished in ms on 2 files with 88 rules using 1 threads. +Finished in ms on 2 files with 103 rules using 1 threads. ---------- CLI result: LintFoundErrors ---------- diff --git a/apps/oxlint/src/snapshots/fixtures__report_unused_directives_-c .oxlintrc.json --report-unused-disable-directives test.js@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__report_unused_directives_-c .oxlintrc.json --report-unused-disable-directives test.js@oxlint.snap index c2676e8ae1418..bdd8ad32c4b44 100644 --- a/apps/oxlint/src/snapshots/fixtures__report_unused_directives_-c .oxlintrc.json --report-unused-disable-directives test.js@oxlint.snap +++ b/apps/oxlint/src/snapshots/fixtures__report_unused_directives_-c .oxlintrc.json --report-unused-disable-directives test.js@oxlint.snap @@ -64,7 +64,7 @@ working directory: fixtures/report_unused_directives `---- Found 7 warnings and 0 errors. -Finished in ms on 1 file with 89 rules using 1 threads. +Finished in ms on 1 file with 104 rules using 1 threads. ---------- CLI result: LintSucceeded ---------- diff --git a/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware -c .oxlintrc.json@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware -c .oxlintrc.json@oxlint.snap index 071bec96bdc7f..3d2067a74e5a8 100644 --- a/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware -c .oxlintrc.json@oxlint.snap +++ b/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware -c .oxlintrc.json@oxlint.snap @@ -6,6 +6,159 @@ arguments: --type-aware -c .oxlintrc.json working directory: fixtures/tsgolint ---------- + x typescript-eslint(await-thenable): Unexpected `await` of a non-Promise (non-"Thenable") value. + ,-[await-thenable/index.ts:3:1] + 2 | + 3 | await 12; + : ^^^^^^^^ + 4 | await (() => {}); + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[await-thenable/index.ts:4:1] + 3 | await 12; + 4 | await (() => {}); + : ^^^^^ + 5 | + `---- + + x typescript-eslint(await-thenable): Unexpected `await` of a non-Promise (non-"Thenable") value. + ,-[await-thenable/index.ts:7:1] + 6 | // non-Promise values + 7 | await Math.random; + : ^^^^^^^^^^^^^^^^^ + 8 | await { then() {} }; + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[await-thenable/index.ts:8:9] + 7 | await Math.random; + 8 | await { then() {} }; + : ^^^^ + 9 | + `---- + + x typescript-eslint(await-thenable): Unexpected `await` of a non-Promise (non-"Thenable") value. + ,-[await-thenable/index.ts:12:1] + 11 | declare const getPromise: () => Promise; + 12 | await getPromise; + : ^^^^^^^^^^^^^^^^ + `---- + + x typescript-eslint(no-array-delete): Using the `delete` operator with an array expression is unsafe. + ,-[no-array-delete/index.ts:4:1] + 3 | declare const arr: number[]; + 4 | delete arr[0]; + : ^^^^^^^^^^^^^ + `---- + + x typescript-eslint(no-base-to-string): '// Examples of incorrect code for no-base-to-string rule + | + | // These will evaluate to '[object Object]' + | ({})' always use Object's default stringification format ('[object Object]') when stringified. + ,-[no-base-to-string/index.ts:4:1] + 3 | // These will evaluate to '[object Object]' + 4 | ({}).toString(); + : ^^^^ + 5 | ({foo: 'bar'}).toString(); + `---- + + x typescript-eslint(no-base-to-string): ' + | ({foo: 'bar'})' always use Object's default stringification format ('[object Object]') when stringified. + ,-[no-base-to-string/index.ts:5:1] + 4 | ({}).toString(); + 5 | ({foo: 'bar'}).toString(); + : ^^^^^^^^^^^^^^ + 6 | ({foo: 'bar'}).toLocaleString(); + `---- + + x typescript-eslint(no-base-to-string): ' + | ({foo: 'bar'})' always use Object's default stringification format ('[object Object]') when stringified. + ,-[no-base-to-string/index.ts:6:1] + 5 | ({foo: 'bar'}).toString(); + 6 | ({foo: 'bar'}).toLocaleString(); + : ^^^^^^^^^^^^^^ + 7 | + `---- + + x typescript-eslint(no-meaningless-void-operator): void operator shouldn't be used on undefined; it should convey that a return value is being ignored + ,-[no-confusing-void-expression/index.ts:7:28] + 6 | // conditional expression + 7 | const result = condition ? void foo() : bar(); + : ^^^^^^^^^^ + 8 | + `---- + + x typescript-eslint(no-confusing-void-expression): Placing a void expression inside another expression is forbidden. Move it to its own statement instead. + ,-[no-confusing-void-expression/index.ts:7:33] + 6 | // conditional expression + 7 | const result = condition ? void foo() : bar(); + : ^^^^^ + 8 | + `---- + + x typescript-eslint(no-meaningless-void-operator): void operator shouldn't be used on undefined; it should convey that a return value is being ignored + ,-[no-confusing-void-expression/index.ts:10:5] + 9 | // void in conditional + 10 | if (void foo()) { + : ^^^^^^^^^^ + 11 | // ... + `---- + + x typescript-eslint(no-confusing-void-expression): Placing a void expression inside another expression is forbidden. Move it to its own statement instead. + ,-[no-confusing-void-expression/index.ts:10:10] + 9 | // void in conditional + 10 | if (void foo()) { + : ^^^^^ + 11 | // ... + `---- + + x typescript-eslint(no-duplicate-type-constituents): Union type constituent is duplicated with 'A'. + ,-[no-duplicate-type-constituents/index.ts:3:17] + 2 | + 3 | type T1 = 'A' | 'A'; + : ^^^ + 4 | + `---- + + x typescript-eslint(no-redundant-type-constituents): 'A' is an 'error' type that acts as 'any' and overrides all other types in this union type. + ,-[no-duplicate-type-constituents/index.ts:5:11] + 4 | + 5 | type T2 = A | A | B; + : ^ + 6 | + `---- + + x typescript-eslint(no-redundant-type-constituents): 'A' is an 'error' type that acts as 'any' and overrides all other types in this union type. + ,-[no-duplicate-type-constituents/index.ts:5:15] + 4 | + 5 | type T2 = A | A | B; + : ^ + 6 | + `---- + + x typescript-eslint(no-redundant-type-constituents): 'B' is an 'error' type that acts as 'any' and overrides all other types in this union type. + ,-[no-duplicate-type-constituents/index.ts:5:19] + 4 | + 5 | type T2 = A | A | B; + : ^ + 6 | + `---- + + x typescript-eslint(no-duplicate-type-constituents): Union type constituent is duplicated with 'foo'. + ,-[no-duplicate-type-constituents/index.ts:14:5] + 13 | | 'bar' + 14 | | 'foo'; + : ^^^^^ + `---- + + x typescript-eslint(no-confusing-void-expression): Returning a void expression from an arrow function shorthand is forbidden. Please add braces to the arrow function. + ,-[no-floating-promises/index.ts:1:51] + 1 | const promise = new Promise((resolve, _reject) => resolve("value")); + : ^^^^^^^^^^^^^^^^ + 2 | promise; + `---- + x typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` | operator. ,-[no-floating-promises/index.ts:2:1] @@ -15,6 +168,15 @@ working directory: fixtures/tsgolint 3 | `---- + x typescript-eslint(require-await): Function has no 'await' expression. + ,-[no-floating-promises/index.ts:4:1] + 3 | + 4 | ,-> async function returnsPromise() { + 5 | | return "value"; + 6 | `-> } + 7 | + `---- + x typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` | operator. ,-[no-floating-promises/index.ts:8:1] @@ -24,6 +186,14 @@ working directory: fixtures/tsgolint 9 | `---- + x typescript-eslint(prefer-promise-reject-errors): Expected the Promise rejection reason to be an Error. + ,-[no-floating-promises/index.ts:10:1] + 9 | + 10 | Promise.reject("value").catch(); + : ^^^^^^^^^^^^^^^^^^^^^^^ + 11 | + `---- + x typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` | operator. ,-[no-floating-promises/index.ts:10:1] @@ -33,6 +203,14 @@ working directory: fixtures/tsgolint 11 | `---- + x typescript-eslint(prefer-promise-reject-errors): Expected the Promise rejection reason to be an Error. + ,-[no-floating-promises/index.ts:12:1] + 11 | + 12 | Promise.reject("value").finally(); + : ^^^^^^^^^^^^^^^^^^^^^^^ + 13 | + `---- + x typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` | operator. ,-[no-floating-promises/index.ts:12:1] @@ -50,6 +228,606 @@ working directory: fixtures/tsgolint : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `---- + x typescript-eslint(require-await): Function has no 'await' expression. + ,-[no-floating-promises/index.ts:14:15] + 13 | + 14 | [1, 2, 3].map(async (x) => x + 1); + : ^^^^^^^^^^^^^^^^^^ + `---- + + x typescript-eslint(no-for-in-array): For-in loops over arrays skips holes, returns indices as strings, and may visit the prototype chain or other enumerable properties. Use a more robust + | iteration method such as for-of or array.forEach instead. + ,-[no-for-in-array/index.ts:5:1] + 4 | + 5 | for (const i in arr) { + : ^^^^^^^^^^^^^^^^^^^^ + 6 | console.log(arr[i]); + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[no-for-in-array/index.ts:6:3] + 5 | for (const i in arr) { + 6 | console.log(arr[i]); + : ^^^^^^^^^^^ + 7 | } + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .log on an `any` value. + ,-[no-for-in-array/index.ts:6:11] + 5 | for (const i in arr) { + 6 | console.log(arr[i]); + : ^^^ + 7 | } + `---- + + x typescript-eslint(no-for-in-array): For-in loops over arrays skips holes, returns indices as strings, and may visit the prototype chain or other enumerable properties. Use a more robust + | iteration method such as for-of or array.forEach instead. + ,-[no-for-in-array/index.ts:9:1] + 8 | + 9 | for (const i in arr) { + : ^^^^^^^^^^^^^^^^^^^^ + 10 | console.log(i, arr[i]); + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[no-for-in-array/index.ts:10:3] + 9 | for (const i in arr) { + 10 | console.log(i, arr[i]); + : ^^^^^^^^^^^ + 11 | } + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .log on an `any` value. + ,-[no-for-in-array/index.ts:10:11] + 9 | for (const i in arr) { + 10 | console.log(i, arr[i]); + : ^^^ + 11 | } + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[no-implied-eval/index.ts:3:1] + 2 | + 3 | setTimeout('alert("Hi!");', 100); + : ^^^^^^^^^^ + 4 | + `---- + + x typescript-eslint(no-implied-eval): Implied eval. Consider passing a function. + ,-[no-implied-eval/index.ts:3:12] + 2 | + 3 | setTimeout('alert("Hi!");', 100); + : ^^^^^^^^^^^^^^^ + 4 | + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[no-implied-eval/index.ts:5:1] + 4 | + 5 | setInterval('alert("Hi!");', 100); + : ^^^^^^^^^^^ + 6 | + `---- + + x typescript-eslint(no-implied-eval): Implied eval. Consider passing a function. + ,-[no-implied-eval/index.ts:5:13] + 4 | + 5 | setInterval('alert("Hi!");', 100); + : ^^^^^^^^^^^^^^^ + 6 | + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[no-implied-eval/index.ts:7:1] + 6 | + 7 | setImmediate('alert("Hi!")'); + : ^^^^^^^^^^^^ + 8 | + `---- + + x typescript-eslint(no-implied-eval): Implied eval. Consider passing a function. + ,-[no-implied-eval/index.ts:7:14] + 6 | + 7 | setImmediate('alert("Hi!")'); + : ^^^^^^^^^^^^^^ + 8 | + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[no-implied-eval/index.ts:9:1] + 8 | + 9 | window.setTimeout('count = 5', 10); + : ^^^^^^^^^^^^^^^^^ + 10 | + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .setTimeout on an `any` value. + ,-[no-implied-eval/index.ts:9:8] + 8 | + 9 | window.setTimeout('count = 5', 10); + : ^^^^^^^^^^ + 10 | + `---- + + x typescript-eslint(no-implied-eval): Implied eval. Consider passing a function. + ,-[no-implied-eval/index.ts:9:19] + 8 | + 9 | window.setTimeout('count = 5', 10); + : ^^^^^^^^^^^ + 10 | + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[no-implied-eval/index.ts:11:1] + 10 | + 11 | window.setInterval('foo = bar', 10); + : ^^^^^^^^^^^^^^^^^^ + 12 | + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .setInterval on an `any` value. + ,-[no-implied-eval/index.ts:11:8] + 10 | + 11 | window.setInterval('foo = bar', 10); + : ^^^^^^^^^^^ + 12 | + `---- + + x typescript-eslint(no-implied-eval): Implied eval. Consider passing a function. + ,-[no-implied-eval/index.ts:11:20] + 10 | + 11 | window.setInterval('foo = bar', 10); + : ^^^^^^^^^^^ + 12 | + `---- + + x typescript-eslint(no-implied-eval): Implied eval. Do not use the Function constructor to create functions. + ,-[no-implied-eval/index.ts:13:12] + 12 | + 13 | const fn = new Function('a', 'b', 'return a + b'); + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x typescript-eslint(no-meaningless-void-operator): void operator shouldn't be used on undefined; it should convey that a return value is being ignored + ,-[no-meaningless-void-operator/index.ts:7:1] + 6 | + 7 | void foo(); // meaningless, foo() already returns void + : ^^^^^^^^^^ + 8 | + `---- + + x typescript-eslint(no-confusing-void-expression): Placing a void expression inside another expression is forbidden. Move it to its own statement instead. + ,-[no-meaningless-void-operator/index.ts:7:6] + 6 | + 7 | void foo(); // meaningless, foo() already returns void + : ^^^^^ + 8 | + `---- + + x typescript-eslint(no-meaningless-void-operator): void operator shouldn't be used on undefined; it should convey that a return value is being ignored + ,-[no-meaningless-void-operator/index.ts:9:1] + 8 | + 9 | void undefined; // meaningless, undefined is already undefined + : ^^^^^^^^^^^^^^ + 10 | + `---- + + x typescript-eslint(no-unsafe-assignment): Unsafe assignment of an any value. + ,-[no-misused-spread/index.ts:13:7] + 12 | const str = 'hello'; + 13 | const obj = { ...str }; // Creates { '0': 'h', '1': 'e', ... } which might be unexpected + : ^^^^^^^^^^^^^^^^ + `---- + + x typescript-eslint(no-mixed-enums): Mixing number and string enums can be confusing. + ,-[no-mixed-enums/index.ts:5:12] + 4 | Open = 1, + 5 | Closed = 'closed', + : ^^^^^^^^ + 6 | } + `---- + + x typescript-eslint(no-mixed-enums): Mixing number and string enums can be confusing. + ,-[no-mixed-enums/index.ts:10:10] + 9 | Up = 'up', + 10 | Down = 2, + : ^ + 11 | Left = 'left', + `---- + + x typescript-eslint(no-redundant-type-constituents): 'unknown' overrides all other types in this union type. + ,-[no-redundant-type-constituents/index.ts:4:20] + 3 | // unknown is redundant in unions + 4 | type T1 = string | unknown; + : ^^^^^^^ + 5 | + `---- + + x typescript-eslint(no-redundant-type-constituents): 'any' overrides all other types in this union type. + ,-[no-redundant-type-constituents/index.ts:7:20] + 6 | // any is redundant in unions + 7 | type T2 = string | any; + : ^^^ + 8 | + `---- + + x typescript-eslint(no-redundant-type-constituents): 'never' is overridden by other types in this union type. + ,-[no-redundant-type-constituents/index.ts:10:20] + 9 | // never is redundant in unions + 10 | type T3 = string | never; + : ^^^^^ + `---- + + x typescript-eslint(no-unnecessary-boolean-literal-compare): This expression unnecessarily compares a boolean value to a boolean instead of using it directly. + ,-[no-unnecessary-boolean-literal-compare/index.ts:5:5] + 4 | + 5 | if (someCondition === true) { + : ^^^^^^^^^^^^^^^^^^^^^^ + 6 | // ... + `---- + + x typescript-eslint(no-unnecessary-boolean-literal-compare): This expression unnecessarily compares a boolean value to a boolean instead of using it directly. + ,-[no-unnecessary-boolean-literal-compare/index.ts:9:5] + 8 | + 9 | if (someCondition === false) { + : ^^^^^^^^^^^^^^^^^^^^^^^ + 10 | // ... + `---- + + x typescript-eslint(no-unnecessary-template-expression): Template literal expression is unnecessary and can be simplified. + ,-[no-unnecessary-template-expression/index.ts:10:15] + 9 | // Template with only literal expressions + 10 | const str4 = `${'Hello'} ${'world'}`; + : ^^^^^^^^^^ + `---- + + x typescript-eslint(no-unnecessary-template-expression): Template literal expression is unnecessary and can be simplified. + ,-[no-unnecessary-template-expression/index.ts:10:26] + 9 | // Template with only literal expressions + 10 | const str4 = `${'Hello'} ${'world'}`; + : ^^^^^^^^^^ + `---- + + x typescript-eslint(no-unnecessary-type-arguments): This is the default value for this type parameter, so it can be omitted. + ,-[no-unnecessary-type-arguments/index.ts:8:25] + 7 | // Unnecessary type argument - string is the default + 8 | const result = identity('hello'); + : ^^^^^^ + 9 | + `---- + + x typescript-eslint(no-unnecessary-type-assertion): This assertion is unnecessary since it does not change the type of the expression. + ,-[no-unnecessary-type-assertion/index.ts:9:16] + 8 | } + 9 | const result = getString() as string; // unnecessary, getString() already returns string + : ^^^^^^^^^^^^^^^^^^^^^ + 10 | + `---- + + x typescript-eslint(no-unnecessary-type-assertion): This assertion is unnecessary since it does not change the type of the expression. + ,-[no-unnecessary-type-assertion/index.ts:12:23] + 11 | const num = 42; + 12 | const alsoRedundant = num as 42; // unnecessary if TypeScript can infer literal type + : ^^^^^^^^^ + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[no-unsafe-argument/index.ts:6:3] + 5 | function takesString(str: string): void { + 6 | console.log(str.length); + : ^^^^^^^^^^^ + 7 | } + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .log on an `any` value. + ,-[no-unsafe-argument/index.ts:6:11] + 5 | function takesString(str: string): void { + 6 | console.log(str.length); + : ^^^ + 7 | } + `---- + + x typescript-eslint(no-unsafe-argument): Unsafe argument of type any assigned to a parameter of type string. + ,-[no-unsafe-argument/index.ts:9:13] + 8 | + 9 | takesString(anyValue); // unsafe + : ^^^^^^^^ + 10 | + `---- + + x typescript-eslint(no-unsafe-argument): Unsafe argument of type any assigned to a parameter of type number. + ,-[no-unsafe-argument/index.ts:12:28] + 11 | declare function takesNumber(num: number): number; + 12 | const result = takesNumber(anyValue); // unsafe + : ^^^^^^^^ + `---- + + x typescript-eslint(no-unsafe-assignment): Unsafe assignment of an any value. + ,-[no-unsafe-assignment/index.ts:5:7] + 4 | + 5 | const str: string = anyValue; // unsafe assignment + : ^^^^^^^^^^^^^^^^^^^^^^ + 6 | + `---- + + x typescript-eslint(no-unsafe-assignment): Unsafe assignment of an any value. + ,-[no-unsafe-assignment/index.ts:8:1] + 7 | let num: number; + 8 | num = anyValue; // unsafe assignment + : ^^^^^^^^^^^^^^ + 9 | + `---- + + x typescript-eslint(no-unsafe-assignment): Unsafe assignment of an any value. + ,-[no-unsafe-assignment/index.ts:11:3] + 10 | const obj = { + 11 | prop: anyValue as any, // unsafe assignment + : ^^^^^^^^^^^^^^^^^^^^^ + 12 | }; + `---- + + x typescript-eslint(no-unnecessary-type-assertion): This assertion is unnecessary since it does not change the type of the expression. + ,-[no-unsafe-assignment/index.ts:11:9] + 10 | const obj = { + 11 | prop: anyValue as any, // unsafe assignment + : ^^^^^^^^^^^^^^^ + 12 | }; + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[no-unsafe-call/index.ts:5:1] + 4 | + 5 | anyValue(); // unsafe call + : ^^^^^^^^ + 6 | + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[no-unsafe-call/index.ts:7:1] + 6 | + 7 | anyValue(1, 2, 3); // unsafe call + : ^^^^^^^^ + 8 | + `---- + + x typescript-eslint(no-unsafe-assignment): Unsafe assignment of an any value. + ,-[no-unsafe-call/index.ts:9:7] + 8 | + 9 | const result = anyValue('hello'); // unsafe call + : ^^^^^^^^^^^^^^^^^^^^^^^^^^ + 10 | + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[no-unsafe-call/index.ts:9:16] + 8 | + 9 | const result = anyValue('hello'); // unsafe call + : ^^^^^^^^ + 10 | + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[no-unsafe-call/index.ts:12:1] + 11 | // Chained unsafe calls + 12 | anyValue().then().catch(); // unsafe + : ^^^^^^^^ + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[no-unsafe-call/index.ts:12:1] + 11 | // Chained unsafe calls + 12 | anyValue().then().catch(); // unsafe + : ^^^^^^^^^^^^^^^ + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[no-unsafe-call/index.ts:12:1] + 11 | // Chained unsafe calls + 12 | anyValue().then().catch(); // unsafe + : ^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .then on an `any` value. + ,-[no-unsafe-call/index.ts:12:12] + 11 | // Chained unsafe calls + 12 | anyValue().then().catch(); // unsafe + : ^^^^ + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .catch on an `any` value. + ,-[no-unsafe-call/index.ts:12:19] + 11 | // Chained unsafe calls + 12 | anyValue().then().catch(); // unsafe + : ^^^^^ + `---- + + x typescript-eslint(no-mixed-enums): Mixing number and string enums can be confusing. + ,-[no-unsafe-enum-comparison/index.ts:4:10] + 3 | enum Status { + 4 | Open = 'open', + : ^^^^^^ + 5 | Closed = 'closed', + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .foo on an `any` value. + ,-[no-unsafe-member-access/index.ts:5:10] + 4 | + 5 | anyValue.foo; // unsafe member access + : ^^^ + 6 | + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .bar on an `any` value. + ,-[no-unsafe-member-access/index.ts:7:10] + 6 | + 7 | anyValue.bar.baz; // unsafe nested member access + : ^^^ + 8 | + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access ['key'] on an `any` value. + ,-[no-unsafe-member-access/index.ts:9:10] + 8 | + 9 | anyValue['key']; // unsafe computed member access + : ^^^^^ + 10 | + `---- + + x typescript-eslint(no-unsafe-assignment): Unsafe assignment of an any value. + ,-[no-unsafe-member-access/index.ts:11:7] + 10 | + 11 | const result = anyValue.method(); // unsafe method access + : ^^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[no-unsafe-member-access/index.ts:11:16] + 10 | + 11 | const result = anyValue.method(); // unsafe method access + : ^^^^^^^^^^^^^^^ + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .method on an `any` value. + ,-[no-unsafe-member-access/index.ts:11:25] + 10 | + 11 | const result = anyValue.method(); // unsafe method access + : ^^^^^^ + `---- + + x typescript-eslint(no-unsafe-return): Unsafe return of a value of type `any`. + ,-[no-unsafe-return/index.ts:6:3] + 5 | function getString(): string { + 6 | return anyValue; // unsafe return + : ^^^^^^^^^^^^^^^^ + 7 | } + `---- + + x typescript-eslint(no-unsafe-return): Unsafe return of a value of type `any`. + ,-[no-unsafe-return/index.ts:9:33] + 8 | + 9 | const getNumber = (): number => anyValue; // unsafe return + : ^^^^^^^^ + 10 | + `---- + + x typescript-eslint(no-unsafe-return): Unsafe return of a value of type `any`. + ,-[no-unsafe-return/index.ts:12:3] + 11 | function processData(): { name: string; age: number } { + 12 | return anyValue; // unsafe return + : ^^^^^^^^^^^^^^^^ + 13 | } + `---- + + x typescript-eslint(no-unsafe-assignment): Unsafe assignment of an any value. + ,-[no-unsafe-type-assertion/index.ts:5:7] + 4 | + 5 | const str = value as any; // unsafe type assertion + : ^^^^^^^^^^^^^^^^^^ + 6 | + `---- + + x typescript-eslint(no-unsafe-type-assertion): Unsafe assertion to `any` detected: consider using a more specific type to ensure safety. + ,-[no-unsafe-type-assertion/index.ts:5:13] + 4 | + 5 | const str = value as any; // unsafe type assertion + : ^^^^^^^^^^^^ + 6 | + `---- + + x typescript-eslint(no-unsafe-type-assertion): Unsafe assertion to `any` detected: consider using a more specific type to ensure safety. + ,-[no-unsafe-type-assertion/index.ts:7:13] + 6 | + 7 | const obj = value as any as string; // double assertion through any + : ^^^^^^^^^^^^ + 8 | + `---- + + x typescript-eslint(no-unsafe-type-assertion): Unsafe assertion from `any` detected: consider using type guards or a safer assertion. + ,-[no-unsafe-type-assertion/index.ts:7:13] + 6 | + 7 | const obj = value as any as string; // double assertion through any + : ^^^^^^^^^^^^^^^^^^^^^^ + 8 | + `---- + + x typescript-eslint(no-unsafe-assignment): Unsafe assignment of an any value. + ,-[no-unsafe-type-assertion/index.ts:10:9] + 9 | function processValue(input: unknown) { + 10 | const processed = input as any; // unsafe + : ^^^^^^^^^^^^^^^^^^^^^^^^ + 11 | return processed.someProperty; + `---- + + x typescript-eslint(no-unsafe-type-assertion): Unsafe assertion to `any` detected: consider using a more specific type to ensure safety. + ,-[no-unsafe-type-assertion/index.ts:10:21] + 9 | function processValue(input: unknown) { + 10 | const processed = input as any; // unsafe + : ^^^^^^^^^^^^ + 11 | return processed.someProperty; + `---- + + x typescript-eslint(no-unsafe-return): Unsafe return of a value of type `any`. + ,-[no-unsafe-type-assertion/index.ts:11:3] + 10 | const processed = input as any; // unsafe + 11 | return processed.someProperty; + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 12 | } + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .someProperty on an `any` value. + ,-[no-unsafe-type-assertion/index.ts:11:20] + 10 | const processed = input as any; // unsafe + 11 | return processed.someProperty; + : ^^^^^^^^^^^^ + 12 | } + `---- + + x typescript-eslint(no-unsafe-unary-minus): Argument of unary negation should be assignable to number | bigint but is unknown instead. + ,-[no-unsafe-unary-minus/index.ts:4:17] + 3 | declare const value: any; + 4 | const result1 = -value; // unsafe on any + : ^^^^^^ + 5 | + `---- + + x typescript-eslint(no-unsafe-unary-minus): Argument of unary negation should be assignable to number | bigint but is "hello" instead. + ,-[no-unsafe-unary-minus/index.ts:7:17] + 6 | declare const str: string; + 7 | const result2 = -str; // unsafe on string + : ^^^^ + 8 | + `---- + + x typescript-eslint(no-unsafe-unary-minus): Argument of unary negation should be assignable to number | bigint but is false instead. + ,-[no-unsafe-unary-minus/index.ts:10:17] + 9 | declare const bool: boolean; + 10 | const result3 = -bool; // unsafe on boolean + : ^^^^^ + 11 | + `---- + + x typescript-eslint(no-unsafe-type-assertion): Unsafe type assertion: type 'string' is more narrow than the original type. + ,-[non-nullable-type-assertion-style/index.ts:6:17] + 5 | // Type assertion when non-null assertion would be clearer + 6 | const result1 = value as string; + : ^^^^^^^^^^^^^^^ + 7 | + `---- + + x typescript-eslint(no-unsafe-type-assertion): Unsafe type assertion: type 'number' is more narrow than the original type. + ,-[non-nullable-type-assertion-style/index.ts:9:17] + 8 | declare const maybe: number | undefined; + 9 | const result2 = maybe as number; + : ^^^^^^^^^^^^^^^ + `---- + + x typescript-eslint(non-nullable-type-assertion-style): Use a ! assertion to more succinctly remove null and undefined from the type. + ,-[non-nullable-type-assertion-style/index.ts:9:17] + 8 | declare const maybe: number | undefined; + 9 | const result2 = maybe as number; + : ^^^^^^^^^^^^^^^ + `---- + x ]8;;https://oxc.rs/docs/guide/usage/linter/rules/eslint/no-debugger.html\eslint(no-debugger)]8;;\: `debugger` statement is not allowed ,-[non-tsgolint.ts:1:1] 1 | debugger; @@ -57,8 +835,553 @@ working directory: fixtures/tsgolint `---- help: Remove the debugger statement -Found 0 warnings and 6 errors. -Finished in ms on 2 files with 2 rules using 1 threads. + x typescript-eslint(only-throw-error): Expected an error object to be thrown. + ,-[only-throw-error/index.ts:3:7] + 2 | + 3 | throw 'error'; // throwing string + : ^^^^^^^ + 4 | + `---- + + x typescript-eslint(only-throw-error): Expected an error object to be thrown. + ,-[only-throw-error/index.ts:5:7] + 4 | + 5 | throw 42; // throwing number + : ^^ + 6 | + `---- + + x typescript-eslint(only-throw-error): Expected an error object to be thrown. + ,-[only-throw-error/index.ts:7:7] + 6 | + 7 | throw true; // throwing boolean + : ^^^^ + 8 | + `---- + + x typescript-eslint(only-throw-error): Expected an error object to be thrown. + ,-[only-throw-error/index.ts:9:7] + 8 | + 9 | throw { message: 'error' }; // throwing plain object + : ^^^^^^^^^^^^^^^^^^^^ + 10 | + `---- + + x typescript-eslint(only-throw-error): Expected an error object to be thrown. + ,-[only-throw-error/index.ts:11:7] + 10 | + 11 | throw null; // throwing null + : ^^^^ + `---- + + x typescript-eslint(prefer-promise-reject-errors): Expected the Promise rejection reason to be an Error. + ,-[prefer-promise-reject-errors/index.ts:3:1] + 2 | + 3 | Promise.reject('error'); // rejecting with string + : ^^^^^^^^^^^^^^^^^^^^^^^ + 4 | + `---- + + x typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` + | operator. + ,-[prefer-promise-reject-errors/index.ts:3:1] + 2 | + 3 | Promise.reject('error'); // rejecting with string + : ^^^^^^^^^^^^^^^^^^^^^^^^ + 4 | + `---- + + x typescript-eslint(prefer-promise-reject-errors): Expected the Promise rejection reason to be an Error. + ,-[prefer-promise-reject-errors/index.ts:5:1] + 4 | + 5 | Promise.reject(42); // rejecting with number + : ^^^^^^^^^^^^^^^^^^ + 6 | + `---- + + x typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` + | operator. + ,-[prefer-promise-reject-errors/index.ts:5:1] + 4 | + 5 | Promise.reject(42); // rejecting with number + : ^^^^^^^^^^^^^^^^^^^ + 6 | + `---- + + x typescript-eslint(prefer-promise-reject-errors): Expected the Promise rejection reason to be an Error. + ,-[prefer-promise-reject-errors/index.ts:7:1] + 6 | + 7 | Promise.reject(true); // rejecting with boolean + : ^^^^^^^^^^^^^^^^^^^^ + 8 | + `---- + + x typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` + | operator. + ,-[prefer-promise-reject-errors/index.ts:7:1] + 6 | + 7 | Promise.reject(true); // rejecting with boolean + : ^^^^^^^^^^^^^^^^^^^^^ + 8 | + `---- + + x typescript-eslint(prefer-promise-reject-errors): Expected the Promise rejection reason to be an Error. + ,-[prefer-promise-reject-errors/index.ts:9:1] + 8 | + 9 | Promise.reject({ message: 'error' }); // rejecting with plain object + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 10 | + `---- + + x typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` + | operator. + ,-[prefer-promise-reject-errors/index.ts:9:1] + 8 | + 9 | Promise.reject({ message: 'error' }); // rejecting with plain object + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 10 | + `---- + + x typescript-eslint(prefer-promise-reject-errors): Expected the Promise rejection reason to be an Error. + ,-[prefer-promise-reject-errors/index.ts:11:1] + 10 | + 11 | Promise.reject(null); // rejecting with null + : ^^^^^^^^^^^^^^^^^^^^ + `---- + + x typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` + | operator. + ,-[prefer-promise-reject-errors/index.ts:11:1] + 10 | + 11 | Promise.reject(null); // rejecting with null + : ^^^^^^^^^^^^^^^^^^^^^ + `---- + + x typescript-eslint(no-unnecessary-type-assertion): This assertion is unnecessary since it does not change the type of the expression. + ,-[prefer-reduce-type-parameter/index.ts:6:13] + 5 | // Casting the result + 6 | const sum = numbers.reduce((acc, val) => acc + val, 0) as number; + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 7 | + `---- + + x typescript-eslint(prefer-reduce-type-parameter): Unnecessary assertion: Array#reduce accepts a type parameter for the default value. + ,-[prefer-reduce-type-parameter/index.ts:12:4] + 11 | return acc; + 12 | }, [] as string[]); + : ^^^^^^^^^^^^^^ + `---- + + x typescript-eslint(prefer-return-this-type): Use `this` type instead. + ,-[prefer-return-this-type/index.ts:6:28] + 5 | + 6 | setValue(value: string): Builder { // Should return 'this' + : ^^^^^^^ + 7 | this.value = value; + `---- + + x typescript-eslint(promise-function-async): Functions that return promises must be async. + ,-[promise-function-async/index.ts:4:1] + 3 | // Function returning Promise without async + 4 | ,-> function fetchData(): Promise { + 5 | | return fetch('/api/data').then(res => res.text()); + 6 | `-> } + 7 | + `---- + + x typescript-eslint(no-unsafe-return): Unsafe return of a value of type `any`. + ,-[promise-function-async/index.ts:5:3] + 4 | function fetchData(): Promise { + 5 | return fetch('/api/data').then(res => res.text()); + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 6 | } + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[promise-function-async/index.ts:5:10] + 4 | function fetchData(): Promise { + 5 | return fetch('/api/data').then(res => res.text()); + : ^^^^^ + 6 | } + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[promise-function-async/index.ts:5:10] + 4 | function fetchData(): Promise { + 5 | return fetch('/api/data').then(res => res.text()); + : ^^^^^^^^^^^^^^^^^^^^^^^ + 6 | } + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .then on an `any` value. + ,-[promise-function-async/index.ts:5:29] + 4 | function fetchData(): Promise { + 5 | return fetch('/api/data').then(res => res.text()); + : ^^^^ + 6 | } + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[promise-function-async/index.ts:5:41] + 4 | function fetchData(): Promise { + 5 | return fetch('/api/data').then(res => res.text()); + : ^^^^^^^^ + 6 | } + `---- + + x typescript-eslint(no-unsafe-return): Unsafe return of a value of type `any`. + ,-[promise-function-async/index.ts:5:41] + 4 | function fetchData(): Promise { + 5 | return fetch('/api/data').then(res => res.text()); + : ^^^^^^^^^^ + 6 | } + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .text on an `any` value. + ,-[promise-function-async/index.ts:5:45] + 4 | function fetchData(): Promise { + 5 | return fetch('/api/data').then(res => res.text()); + : ^^^^ + 6 | } + `---- + + x typescript-eslint(promise-function-async): Functions that return promises must be async. + ,-[promise-function-async/index.ts:10:3] + 9 | class DataService { + 10 | ,-> getData(): Promise { + 11 | | return fetch('/api/data').then(res => res.json()); + 12 | `-> } + 13 | } + `---- + + x typescript-eslint(no-unsafe-return): Unsafe return of a value of type `any`. + ,-[promise-function-async/index.ts:11:5] + 10 | getData(): Promise { + 11 | return fetch('/api/data').then(res => res.json()); + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 12 | } + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[promise-function-async/index.ts:11:12] + 10 | getData(): Promise { + 11 | return fetch('/api/data').then(res => res.json()); + : ^^^^^ + 12 | } + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[promise-function-async/index.ts:11:12] + 10 | getData(): Promise { + 11 | return fetch('/api/data').then(res => res.json()); + : ^^^^^^^^^^^^^^^^^^^^^^^ + 12 | } + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .then on an `any` value. + ,-[promise-function-async/index.ts:11:31] + 10 | getData(): Promise { + 11 | return fetch('/api/data').then(res => res.json()); + : ^^^^ + 12 | } + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[promise-function-async/index.ts:11:43] + 10 | getData(): Promise { + 11 | return fetch('/api/data').then(res => res.json()); + : ^^^^^^^^ + 12 | } + `---- + + x typescript-eslint(no-unsafe-return): Unsafe return of a value of type `any`. + ,-[promise-function-async/index.ts:11:43] + 10 | getData(): Promise { + 11 | return fetch('/api/data').then(res => res.json()); + : ^^^^^^^^^^ + 12 | } + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .json on an `any` value. + ,-[promise-function-async/index.ts:11:47] + 10 | getData(): Promise { + 11 | return fetch('/api/data').then(res => res.json()); + : ^^^^ + 12 | } + `---- + + x typescript-eslint(related-getter-setter-pairs): `get()` type should be assignable to its equivalent `set()` type. + ,-[related-getter-setter-pairs/index.ts:7:16] + 6 | // Getter and setter with incompatible types + 7 | get value(): string { + : ^^^^^^ + 8 | return this._value.toString(); + `---- + + x typescript-eslint(require-array-sort-compare): Require 'compare' argument. + ,-[require-array-sort-compare/index.ts:4:1] + 3 | const numbers = [3, 1, 4, 1, 5]; + 4 | numbers.sort(); // Lexicographic sort, not numeric + : ^^^^^^^^^^^^^^ + 5 | + `---- + + x typescript-eslint(require-array-sort-compare): Require 'compare' argument. + ,-[require-array-sort-compare/index.ts:9:1] + 8 | + 9 | [3, 1, 4].sort(); // Will sort as strings: ['1', '3', '4'] + : ^^^^^^^^^^^^^^^^ + `---- + + x typescript-eslint(require-await): Function has no 'await' expression. + ,-[require-await/index.ts:4:1] + 3 | // Async function without await + 4 | ,-> async function fetchData() { + 5 | | return fetch('/api/data'); + 6 | `-> } + 7 | + `---- + + x typescript-eslint(no-unsafe-return): Unsafe return of a value of type `any`. + ,-[require-await/index.ts:5:3] + 4 | async function fetchData() { + 5 | return fetch('/api/data'); + : ^^^^^^^^^^^^^^^^^^^^^^^^^^ + 6 | } + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[require-await/index.ts:5:10] + 4 | async function fetchData() { + 5 | return fetch('/api/data'); + : ^^^^^ + 6 | } + `---- + + x typescript-eslint(require-await): Function has no 'await' expression. + ,-[require-await/index.ts:9:21] + 8 | // Async arrow function without await + 9 | ,-> const processData = async () => { + 10 | | return someData.map(x => x * 2); + 11 | `-> }; + `---- + + x typescript-eslint(no-unsafe-return): Unsafe return of a value of type `any`. + ,-[require-await/index.ts:10:3] + 9 | const processData = async () => { + 10 | return someData.map(x => x * 2); + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 11 | }; + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[require-await/index.ts:10:10] + 9 | const processData = async () => { + 10 | return someData.map(x => x * 2); + : ^^^^^^^^^^^^ + 11 | }; + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .map on an `any` value. + ,-[require-await/index.ts:10:19] + 9 | const processData = async () => { + 10 | return someData.map(x => x * 2); + : ^^^ + 11 | }; + `---- + + x typescript-eslint(no-unsafe-assignment): Unsafe assignment of an any value. + ,-[restrict-plus-operands/index.ts:11:7] + 10 | const result2 = str + bool; // string + boolean + 11 | const result3 = num + bool; // number + boolean + : ^^^^^^^^^^^^^^^^^^^^ + 12 | const result4 = obj + str; // object + string + `---- + + x typescript-eslint(restrict-template-expressions): Invalid type "symbol" of template literal expression. + ,-[restrict-template-expressions/index.ts:12:25] + 11 | // Symbols might not be what you expect + 12 | const str2 = `Symbol: ${sym}`; + : ^^^ + 13 | + `---- + + x typescript-eslint(restrict-template-expressions): Invalid type "Function" of template literal expression. + ,-[restrict-template-expressions/index.ts:15:27] + 14 | // Functions become their string representation + 15 | const str3 = `Function: ${fn}`; + : ^^ + 16 | + `---- + + x typescript-eslint(restrict-template-expressions): Invalid type "number[]" of template literal expression. + ,-[restrict-template-expressions/index.ts:18:24] + 17 | // Arrays of unknown might be unsafe + 18 | const str4 = `Array: ${arr}`; + : ^^^ + `---- + + x typescript-eslint(require-await): Function has no 'await' expression. + ,-[return-await/index.ts:4:1] + 3 | // If configured to require await: + 4 | ,-> async function fetchData() { + 5 | | return fetch('/api/data'); // Should be: return await fetch('/api/data'); + 6 | `-> } + 7 | + `---- + + x typescript-eslint(no-unsafe-return): Unsafe return of a value of type `any`. + ,-[return-await/index.ts:5:3] + 4 | async function fetchData() { + 5 | return fetch('/api/data'); // Should be: return await fetch('/api/data'); + : ^^^^^^^^^^^^^^^^^^^^^^^^^^ + 6 | } + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[return-await/index.ts:5:10] + 4 | async function fetchData() { + 5 | return fetch('/api/data'); // Should be: return await fetch('/api/data'); + : ^^^^^ + 6 | } + `---- + + x typescript-eslint(require-await): Function has no 'await' expression. + ,-[return-await/index.ts:8:1] + 7 | + 8 | ,-> async function processData() { + 9 | | return someAsyncOperation(); // Should be: return await someAsyncOperation(); + 10 | `-> } + `---- + + x typescript-eslint(no-unsafe-return): Unsafe return of a value of type `any`. + ,-[return-await/index.ts:9:3] + 8 | async function processData() { + 9 | return someAsyncOperation(); // Should be: return await someAsyncOperation(); + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 10 | } + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[return-await/index.ts:9:10] + 8 | async function processData() { + 9 | return someAsyncOperation(); // Should be: return await someAsyncOperation(); + : ^^^^^^^^^^^^^^^^^^ + 10 | } + `---- + + x typescript-eslint(switch-exhaustiveness-check): Switch is not exhaustive + ,-[switch-exhaustiveness-check/index.ts:6:11] + 5 | function handleStatus(status: Status) { + 6 | switch (status) { + : ^^^^^^ + 7 | case 'pending': + `---- + + x typescript-eslint(no-unsafe-enum-comparison): The case statement does not have a shared enum type with the switch predicate. + ,-[switch-exhaustiveness-check/index.ts:7:5] + 6 | switch (status) { + 7 | ,-> case 'pending': + 8 | `-> return 'Waiting for approval'; + 9 | case 'approved': + `---- + + x typescript-eslint(no-unsafe-enum-comparison): The case statement does not have a shared enum type with the switch predicate. + ,-[switch-exhaustiveness-check/index.ts:9:5] + 8 | return 'Waiting for approval'; + 9 | ,-> case 'approved': + 10 | `-> return 'Request approved'; + 11 | // Missing 'rejected' case + `---- + + x typescript-eslint(no-unsafe-assignment): Unsafe assignment of an any value. + ,-[unbound-method/index.ts:18:7] + 17 | // Unbound method call - 'this' context lost + 18 | const getValue = obj.getValue; + : ^^^^^^^^^^^^^^^^^^^^^^^ + 19 | const result = getValue(); // 'this' is undefined + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .getValue on an `any` value. + ,-[unbound-method/index.ts:18:22] + 17 | // Unbound method call - 'this' context lost + 18 | const getValue = obj.getValue; + : ^^^^^^^^ + 19 | const result = getValue(); // 'this' is undefined + `---- + + x typescript-eslint(no-unsafe-assignment): Unsafe assignment of an any value. + ,-[unbound-method/index.ts:19:7] + 18 | const getValue = obj.getValue; + 19 | const result = getValue(); // 'this' is undefined + : ^^^^^^^^^^^^^^^^^^^ + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[unbound-method/index.ts:19:16] + 18 | const getValue = obj.getValue; + 19 | const result = getValue(); // 'this' is undefined + : ^^^^^^^^ + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[use-unknown-in-catch-callback-variable/index.ts:4:3] + 3 | try { + 4 | somethingRisky(); + : ^^^^^^^^^^^^^^ + 5 | } catch (error: any) { // Should use 'unknown' + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[use-unknown-in-catch-callback-variable/index.ts:6:3] + 5 | } catch (error: any) { // Should use 'unknown' + 6 | console.log(error.message); // Unsafe access + : ^^^^^^^^^^^ + 7 | error.someMethod(); // Unsafe call + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .log on an `any` value. + ,-[use-unknown-in-catch-callback-variable/index.ts:6:11] + 5 | } catch (error: any) { // Should use 'unknown' + 6 | console.log(error.message); // Unsafe access + : ^^^ + 7 | error.someMethod(); // Unsafe call + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .message on an `any` value. + ,-[use-unknown-in-catch-callback-variable/index.ts:6:21] + 5 | } catch (error: any) { // Should use 'unknown' + 6 | console.log(error.message); // Unsafe access + : ^^^^^^^ + 7 | error.someMethod(); // Unsafe call + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[use-unknown-in-catch-callback-variable/index.ts:7:3] + 6 | console.log(error.message); // Unsafe access + 7 | error.someMethod(); // Unsafe call + : ^^^^^^^^^^^^^^^^ + 8 | } + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .someMethod on an `any` value. + ,-[use-unknown-in-catch-callback-variable/index.ts:7:9] + 6 | console.log(error.message); // Unsafe access + 7 | error.someMethod(); // Unsafe call + : ^^^^^^^^^^ + 8 | } + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[use-unknown-in-catch-callback-variable/index.ts:12:3] + 11 | try { + 12 | somethingRisky(); + : ^^^^^^^^^^^^^^ + 13 | } catch (error) { // Should explicitly type as 'unknown' + `---- + +Found 0 warnings and 173 errors. +Finished in ms on 40 files with 40 rules using 1 threads. ---------- CLI result: LintFoundErrors ---------- diff --git a/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware no-floating-promises -c config-test.json@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware no-floating-promises -c config-test.json@oxlint.snap new file mode 100644 index 0000000000000..4539d58e3a75d --- /dev/null +++ b/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware no-floating-promises -c config-test.json@oxlint.snap @@ -0,0 +1,109 @@ +--- +source: apps/oxlint/src/tester.rs +--- +########## +arguments: --type-aware no-floating-promises -c config-test.json +working directory: fixtures/tsgolint +---------- + + ! typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` + | operator. + ,-[no-floating-promises/index.ts:2:1] + 1 | const promise = new Promise((resolve, _reject) => resolve("value")); + 2 | promise; + : ^^^^^^^^ + 3 | + `---- + + ! typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` + | operator. + ,-[no-floating-promises/index.ts:8:1] + 7 | + 8 | returnsPromise().then(() => {}); + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 9 | + `---- + + ! typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` + | operator. + ,-[no-floating-promises/index.ts:10:1] + 9 | + 10 | Promise.reject("value").catch(); + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 11 | + `---- + + ! typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` + | operator. + ,-[no-floating-promises/index.ts:12:1] + 11 | + 12 | Promise.reject("value").finally(); + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 13 | + `---- + + ! typescript-eslint(no-floating-promises): An array of Promises may be unintentional. Consider handling the promises' fulfillment or rejection with Promise.all or similar, or explicitly marking + | the expression as ignored with the `void` operator. + ,-[no-floating-promises/index.ts:14:1] + 13 | + 14 | [1, 2, 3].map(async (x) => x + 1); + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + ! typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` + | operator. + ,-[no-floating-promises/src/index.ts:2:1] + 1 | const promise = new Promise((resolve, _reject) => resolve("value")); + 2 | promise; + : ^^^^^^^^ + 3 | + `---- + + ! typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` + | operator. + ,-[no-floating-promises/src/index.ts:8:1] + 7 | + 8 | returnsPromise().then(() => {}); + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 9 | + `---- + + ! typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` + | operator. + ,-[no-floating-promises/src/index.ts:10:1] + 9 | + 10 | Promise.reject("value").catch(); + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 11 | + `---- + + ! typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` + | operator. + ,-[no-floating-promises/src/index.ts:12:1] + 11 | + 12 | Promise.reject("value").finally(); + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 13 | + `---- + + ! typescript-eslint(no-floating-promises): An array of Promises may be unintentional. Consider handling the promises' fulfillment or rejection with Promise.all or similar, or explicitly marking + | the expression as ignored with the `void` operator. + ,-[no-floating-promises/src/index.ts:14:1] + 13 | + 14 | [1, 2, 3].map(async (x) => x + 1); + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + ! typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` + | operator. + ,-[no-floating-promises/src/overrides.ts:4:1] + 3 | } + 4 | returnsPromise().then(() => {}); + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + +Found 11 warnings and 0 errors. +Finished in ms on 3 files with 1 rules using 1 threads. +---------- +CLI result: LintSucceeded +---------- diff --git a/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware no-floating-promises@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware no-floating-promises@oxlint.snap new file mode 100644 index 0000000000000..9d0df432786d6 --- /dev/null +++ b/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware no-floating-promises@oxlint.snap @@ -0,0 +1,148 @@ +--- +source: apps/oxlint/src/tester.rs +--- +########## +arguments: --type-aware no-floating-promises +working directory: fixtures/tsgolint +---------- + + x typescript-eslint(no-confusing-void-expression): Returning a void expression from an arrow function shorthand is forbidden. Please add braces to the arrow function. + ,-[no-floating-promises/index.ts:1:51] + 1 | const promise = new Promise((resolve, _reject) => resolve("value")); + : ^^^^^^^^^^^^^^^^ + 2 | promise; + `---- + + x typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` + | operator. + ,-[no-floating-promises/index.ts:2:1] + 1 | const promise = new Promise((resolve, _reject) => resolve("value")); + 2 | promise; + : ^^^^^^^^ + 3 | + `---- + + x typescript-eslint(require-await): Function has no 'await' expression. + ,-[no-floating-promises/index.ts:4:1] + 3 | + 4 | ,-> async function returnsPromise() { + 5 | | return "value"; + 6 | `-> } + 7 | + `---- + + x typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` + | operator. + ,-[no-floating-promises/index.ts:8:1] + 7 | + 8 | returnsPromise().then(() => {}); + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 9 | + `---- + + x typescript-eslint(prefer-promise-reject-errors): Expected the Promise rejection reason to be an Error. + ,-[no-floating-promises/index.ts:10:1] + 9 | + 10 | Promise.reject("value").catch(); + : ^^^^^^^^^^^^^^^^^^^^^^^ + 11 | + `---- + + x typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` + | operator. + ,-[no-floating-promises/index.ts:10:1] + 9 | + 10 | Promise.reject("value").catch(); + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 11 | + `---- + + x typescript-eslint(prefer-promise-reject-errors): Expected the Promise rejection reason to be an Error. + ,-[no-floating-promises/index.ts:12:1] + 11 | + 12 | Promise.reject("value").finally(); + : ^^^^^^^^^^^^^^^^^^^^^^^ + 13 | + `---- + + x typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` + | operator. + ,-[no-floating-promises/index.ts:12:1] + 11 | + 12 | Promise.reject("value").finally(); + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 13 | + `---- + + x typescript-eslint(no-floating-promises): An array of Promises may be unintentional. Consider handling the promises' fulfillment or rejection with Promise.all or similar, or explicitly marking + | the expression as ignored with the `void` operator. + ,-[no-floating-promises/index.ts:14:1] + 13 | + 14 | [1, 2, 3].map(async (x) => x + 1); + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x typescript-eslint(require-await): Function has no 'await' expression. + ,-[no-floating-promises/index.ts:14:15] + 13 | + 14 | [1, 2, 3].map(async (x) => x + 1); + : ^^^^^^^^^^^^^^^^^^ + `---- + + ! typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` + | operator. + ,-[no-floating-promises/src/index.ts:2:1] + 1 | const promise = new Promise((resolve, _reject) => resolve("value")); + 2 | promise; + : ^^^^^^^^ + 3 | + `---- + + ! typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` + | operator. + ,-[no-floating-promises/src/index.ts:8:1] + 7 | + 8 | returnsPromise().then(() => {}); + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 9 | + `---- + + ! typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` + | operator. + ,-[no-floating-promises/src/index.ts:10:1] + 9 | + 10 | Promise.reject("value").catch(); + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 11 | + `---- + + ! typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` + | operator. + ,-[no-floating-promises/src/index.ts:12:1] + 11 | + 12 | Promise.reject("value").finally(); + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 13 | + `---- + + ! typescript-eslint(no-floating-promises): An array of Promises may be unintentional. Consider handling the promises' fulfillment or rejection with Promise.all or similar, or explicitly marking + | the expression as ignored with the `void` operator. + ,-[no-floating-promises/src/index.ts:14:1] + 13 | + 14 | [1, 2, 3].map(async (x) => x + 1); + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` + | operator. + ,-[no-floating-promises/src/overrides.ts:4:1] + 3 | } + 4 | returnsPromise().then(() => {}); + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + +Found 5 warnings and 11 errors. +Finished in ms on 3 files using 1 threads. +---------- +CLI result: LintFoundErrors +---------- diff --git a/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware@oxlint.snap b/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware@oxlint.snap index 1f85bfa8fc4ba..5cf0241ed86f1 100644 --- a/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware@oxlint.snap +++ b/apps/oxlint/src/snapshots/fixtures__tsgolint_--type-aware@oxlint.snap @@ -6,6 +6,159 @@ arguments: --type-aware working directory: fixtures/tsgolint ---------- + x typescript-eslint(await-thenable): Unexpected `await` of a non-Promise (non-"Thenable") value. + ,-[await-thenable/index.ts:3:1] + 2 | + 3 | await 12; + : ^^^^^^^^ + 4 | await (() => {}); + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[await-thenable/index.ts:4:1] + 3 | await 12; + 4 | await (() => {}); + : ^^^^^ + 5 | + `---- + + x typescript-eslint(await-thenable): Unexpected `await` of a non-Promise (non-"Thenable") value. + ,-[await-thenable/index.ts:7:1] + 6 | // non-Promise values + 7 | await Math.random; + : ^^^^^^^^^^^^^^^^^ + 8 | await { then() {} }; + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[await-thenable/index.ts:8:9] + 7 | await Math.random; + 8 | await { then() {} }; + : ^^^^ + 9 | + `---- + + x typescript-eslint(await-thenable): Unexpected `await` of a non-Promise (non-"Thenable") value. + ,-[await-thenable/index.ts:12:1] + 11 | declare const getPromise: () => Promise; + 12 | await getPromise; + : ^^^^^^^^^^^^^^^^ + `---- + + x typescript-eslint(no-array-delete): Using the `delete` operator with an array expression is unsafe. + ,-[no-array-delete/index.ts:4:1] + 3 | declare const arr: number[]; + 4 | delete arr[0]; + : ^^^^^^^^^^^^^ + `---- + + x typescript-eslint(no-base-to-string): '// Examples of incorrect code for no-base-to-string rule + | + | // These will evaluate to '[object Object]' + | ({})' always use Object's default stringification format ('[object Object]') when stringified. + ,-[no-base-to-string/index.ts:4:1] + 3 | // These will evaluate to '[object Object]' + 4 | ({}).toString(); + : ^^^^ + 5 | ({foo: 'bar'}).toString(); + `---- + + x typescript-eslint(no-base-to-string): ' + | ({foo: 'bar'})' always use Object's default stringification format ('[object Object]') when stringified. + ,-[no-base-to-string/index.ts:5:1] + 4 | ({}).toString(); + 5 | ({foo: 'bar'}).toString(); + : ^^^^^^^^^^^^^^ + 6 | ({foo: 'bar'}).toLocaleString(); + `---- + + x typescript-eslint(no-base-to-string): ' + | ({foo: 'bar'})' always use Object's default stringification format ('[object Object]') when stringified. + ,-[no-base-to-string/index.ts:6:1] + 5 | ({foo: 'bar'}).toString(); + 6 | ({foo: 'bar'}).toLocaleString(); + : ^^^^^^^^^^^^^^ + 7 | + `---- + + x typescript-eslint(no-meaningless-void-operator): void operator shouldn't be used on undefined; it should convey that a return value is being ignored + ,-[no-confusing-void-expression/index.ts:7:28] + 6 | // conditional expression + 7 | const result = condition ? void foo() : bar(); + : ^^^^^^^^^^ + 8 | + `---- + + x typescript-eslint(no-confusing-void-expression): Placing a void expression inside another expression is forbidden. Move it to its own statement instead. + ,-[no-confusing-void-expression/index.ts:7:33] + 6 | // conditional expression + 7 | const result = condition ? void foo() : bar(); + : ^^^^^ + 8 | + `---- + + x typescript-eslint(no-meaningless-void-operator): void operator shouldn't be used on undefined; it should convey that a return value is being ignored + ,-[no-confusing-void-expression/index.ts:10:5] + 9 | // void in conditional + 10 | if (void foo()) { + : ^^^^^^^^^^ + 11 | // ... + `---- + + x typescript-eslint(no-confusing-void-expression): Placing a void expression inside another expression is forbidden. Move it to its own statement instead. + ,-[no-confusing-void-expression/index.ts:10:10] + 9 | // void in conditional + 10 | if (void foo()) { + : ^^^^^ + 11 | // ... + `---- + + x typescript-eslint(no-duplicate-type-constituents): Union type constituent is duplicated with 'A'. + ,-[no-duplicate-type-constituents/index.ts:3:17] + 2 | + 3 | type T1 = 'A' | 'A'; + : ^^^ + 4 | + `---- + + x typescript-eslint(no-redundant-type-constituents): 'A' is an 'error' type that acts as 'any' and overrides all other types in this union type. + ,-[no-duplicate-type-constituents/index.ts:5:11] + 4 | + 5 | type T2 = A | A | B; + : ^ + 6 | + `---- + + x typescript-eslint(no-redundant-type-constituents): 'A' is an 'error' type that acts as 'any' and overrides all other types in this union type. + ,-[no-duplicate-type-constituents/index.ts:5:15] + 4 | + 5 | type T2 = A | A | B; + : ^ + 6 | + `---- + + x typescript-eslint(no-redundant-type-constituents): 'B' is an 'error' type that acts as 'any' and overrides all other types in this union type. + ,-[no-duplicate-type-constituents/index.ts:5:19] + 4 | + 5 | type T2 = A | A | B; + : ^ + 6 | + `---- + + x typescript-eslint(no-duplicate-type-constituents): Union type constituent is duplicated with 'foo'. + ,-[no-duplicate-type-constituents/index.ts:14:5] + 13 | | 'bar' + 14 | | 'foo'; + : ^^^^^ + `---- + + x typescript-eslint(no-confusing-void-expression): Returning a void expression from an arrow function shorthand is forbidden. Please add braces to the arrow function. + ,-[no-floating-promises/index.ts:1:51] + 1 | const promise = new Promise((resolve, _reject) => resolve("value")); + : ^^^^^^^^^^^^^^^^ + 2 | promise; + `---- + x typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` | operator. ,-[no-floating-promises/index.ts:2:1] @@ -15,6 +168,15 @@ working directory: fixtures/tsgolint 3 | `---- + x typescript-eslint(require-await): Function has no 'await' expression. + ,-[no-floating-promises/index.ts:4:1] + 3 | + 4 | ,-> async function returnsPromise() { + 5 | | return "value"; + 6 | `-> } + 7 | + `---- + x typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` | operator. ,-[no-floating-promises/index.ts:8:1] @@ -24,6 +186,14 @@ working directory: fixtures/tsgolint 9 | `---- + x typescript-eslint(prefer-promise-reject-errors): Expected the Promise rejection reason to be an Error. + ,-[no-floating-promises/index.ts:10:1] + 9 | + 10 | Promise.reject("value").catch(); + : ^^^^^^^^^^^^^^^^^^^^^^^ + 11 | + `---- + x typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` | operator. ,-[no-floating-promises/index.ts:10:1] @@ -33,6 +203,14 @@ working directory: fixtures/tsgolint 11 | `---- + x typescript-eslint(prefer-promise-reject-errors): Expected the Promise rejection reason to be an Error. + ,-[no-floating-promises/index.ts:12:1] + 11 | + 12 | Promise.reject("value").finally(); + : ^^^^^^^^^^^^^^^^^^^^^^^ + 13 | + `---- + x typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` | operator. ,-[no-floating-promises/index.ts:12:1] @@ -50,6 +228,13 @@ working directory: fixtures/tsgolint : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `---- + x typescript-eslint(require-await): Function has no 'await' expression. + ,-[no-floating-promises/index.ts:14:15] + 13 | + 14 | [1, 2, 3].map(async (x) => x + 1); + : ^^^^^^^^^^^^^^^^^^ + `---- + ! typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` | operator. ,-[no-floating-promises/src/index.ts:2:1] @@ -102,6 +287,648 @@ working directory: fixtures/tsgolint : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `---- + x typescript-eslint(no-for-in-array): For-in loops over arrays skips holes, returns indices as strings, and may visit the prototype chain or other enumerable properties. Use a more robust + | iteration method such as for-of or array.forEach instead. + ,-[no-for-in-array/index.ts:5:1] + 4 | + 5 | for (const i in arr) { + : ^^^^^^^^^^^^^^^^^^^^ + 6 | console.log(arr[i]); + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[no-for-in-array/index.ts:6:3] + 5 | for (const i in arr) { + 6 | console.log(arr[i]); + : ^^^^^^^^^^^ + 7 | } + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .log on an `any` value. + ,-[no-for-in-array/index.ts:6:11] + 5 | for (const i in arr) { + 6 | console.log(arr[i]); + : ^^^ + 7 | } + `---- + + x typescript-eslint(no-for-in-array): For-in loops over arrays skips holes, returns indices as strings, and may visit the prototype chain or other enumerable properties. Use a more robust + | iteration method such as for-of or array.forEach instead. + ,-[no-for-in-array/index.ts:9:1] + 8 | + 9 | for (const i in arr) { + : ^^^^^^^^^^^^^^^^^^^^ + 10 | console.log(i, arr[i]); + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[no-for-in-array/index.ts:10:3] + 9 | for (const i in arr) { + 10 | console.log(i, arr[i]); + : ^^^^^^^^^^^ + 11 | } + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .log on an `any` value. + ,-[no-for-in-array/index.ts:10:11] + 9 | for (const i in arr) { + 10 | console.log(i, arr[i]); + : ^^^ + 11 | } + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[no-implied-eval/index.ts:3:1] + 2 | + 3 | setTimeout('alert("Hi!");', 100); + : ^^^^^^^^^^ + 4 | + `---- + + x typescript-eslint(no-implied-eval): Implied eval. Consider passing a function. + ,-[no-implied-eval/index.ts:3:12] + 2 | + 3 | setTimeout('alert("Hi!");', 100); + : ^^^^^^^^^^^^^^^ + 4 | + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[no-implied-eval/index.ts:5:1] + 4 | + 5 | setInterval('alert("Hi!");', 100); + : ^^^^^^^^^^^ + 6 | + `---- + + x typescript-eslint(no-implied-eval): Implied eval. Consider passing a function. + ,-[no-implied-eval/index.ts:5:13] + 4 | + 5 | setInterval('alert("Hi!");', 100); + : ^^^^^^^^^^^^^^^ + 6 | + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[no-implied-eval/index.ts:7:1] + 6 | + 7 | setImmediate('alert("Hi!")'); + : ^^^^^^^^^^^^ + 8 | + `---- + + x typescript-eslint(no-implied-eval): Implied eval. Consider passing a function. + ,-[no-implied-eval/index.ts:7:14] + 6 | + 7 | setImmediate('alert("Hi!")'); + : ^^^^^^^^^^^^^^ + 8 | + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[no-implied-eval/index.ts:9:1] + 8 | + 9 | window.setTimeout('count = 5', 10); + : ^^^^^^^^^^^^^^^^^ + 10 | + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .setTimeout on an `any` value. + ,-[no-implied-eval/index.ts:9:8] + 8 | + 9 | window.setTimeout('count = 5', 10); + : ^^^^^^^^^^ + 10 | + `---- + + x typescript-eslint(no-implied-eval): Implied eval. Consider passing a function. + ,-[no-implied-eval/index.ts:9:19] + 8 | + 9 | window.setTimeout('count = 5', 10); + : ^^^^^^^^^^^ + 10 | + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[no-implied-eval/index.ts:11:1] + 10 | + 11 | window.setInterval('foo = bar', 10); + : ^^^^^^^^^^^^^^^^^^ + 12 | + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .setInterval on an `any` value. + ,-[no-implied-eval/index.ts:11:8] + 10 | + 11 | window.setInterval('foo = bar', 10); + : ^^^^^^^^^^^ + 12 | + `---- + + x typescript-eslint(no-implied-eval): Implied eval. Consider passing a function. + ,-[no-implied-eval/index.ts:11:20] + 10 | + 11 | window.setInterval('foo = bar', 10); + : ^^^^^^^^^^^ + 12 | + `---- + + x typescript-eslint(no-implied-eval): Implied eval. Do not use the Function constructor to create functions. + ,-[no-implied-eval/index.ts:13:12] + 12 | + 13 | const fn = new Function('a', 'b', 'return a + b'); + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x typescript-eslint(no-meaningless-void-operator): void operator shouldn't be used on undefined; it should convey that a return value is being ignored + ,-[no-meaningless-void-operator/index.ts:7:1] + 6 | + 7 | void foo(); // meaningless, foo() already returns void + : ^^^^^^^^^^ + 8 | + `---- + + x typescript-eslint(no-confusing-void-expression): Placing a void expression inside another expression is forbidden. Move it to its own statement instead. + ,-[no-meaningless-void-operator/index.ts:7:6] + 6 | + 7 | void foo(); // meaningless, foo() already returns void + : ^^^^^ + 8 | + `---- + + x typescript-eslint(no-meaningless-void-operator): void operator shouldn't be used on undefined; it should convey that a return value is being ignored + ,-[no-meaningless-void-operator/index.ts:9:1] + 8 | + 9 | void undefined; // meaningless, undefined is already undefined + : ^^^^^^^^^^^^^^ + 10 | + `---- + + x typescript-eslint(no-misused-spread): Using the spread operator on Promise in an object can cause unexpected behavior. Did you forget to await the promise? + ,-[no-misused-spread/index.ts:2:25] + 1 | declare const promise: Promise; + 2 | const spreadPromise = { ...promise }; + : ^^^^^^^^^^ + 3 | + `---- + + x typescript-eslint(no-misused-spread): Using the spread operator on a function without additional properties can cause unexpected behavior. Did you forget to call the function? + ,-[no-misused-spread/index.ts:5:27] + 4 | declare function getObject(): Record; + 5 | const getObjectSpread = { ...getObject }; + : ^^^^^^^^^^^^ + 6 | + `---- + + x typescript-eslint(no-misused-spread): Using the spread operator on a Map in an object will result in an empty object. Did you mean to use `Object.fromEntries(map)` instead? + ,-[no-misused-spread/index.ts:8:21] + 7 | declare const map: Map; + 8 | const mapSpread = { ...map }; + : ^^^^^^ + 9 | + `---- + + x typescript-eslint(no-misused-spread): Using the spread operator on a string can mishandle special characters, as can `.split("")`. + | '- `...` produces Unicode code points, which will decompose complex emojis into individual emojis- .split("") produces UTF-16 code units, which breaks rich characters in many languagesConsider + | using `Intl.Segmenter` for locale-aware string decomposition.Otherwise, if you don't need to preserve emojis or other non-Ascii characters, disable this lint rule on this line or configure the + | 'allow' rule option. + ,-[no-misused-spread/index.ts:11:21] + 10 | declare const userName: string; + 11 | const characters = [...userName]; + : ^^^^^^^^^^^ + `---- + + x typescript-eslint(no-mixed-enums): Mixing number and string enums can be confusing. + ,-[no-mixed-enums/index.ts:4:10] + 3 | enum Status { + 4 | Open = 1, + : ^ + 5 | Closed = 'closed', + `---- + + x typescript-eslint(no-mixed-enums): Mixing number and string enums can be confusing. + ,-[no-mixed-enums/index.ts:10:10] + 9 | Up = 'up', + 10 | Down = 2, + : ^ + 11 | Left = 'left', + `---- + + x typescript-eslint(no-redundant-type-constituents): 'unknown' overrides all other types in this union type. + ,-[no-redundant-type-constituents/index.ts:4:20] + 3 | // unknown is redundant in unions + 4 | type T1 = string | unknown; + : ^^^^^^^ + 5 | + `---- + + x typescript-eslint(no-redundant-type-constituents): 'any' overrides all other types in this union type. + ,-[no-redundant-type-constituents/index.ts:7:20] + 6 | // any is redundant in unions + 7 | type T2 = string | any; + : ^^^ + 8 | + `---- + + x typescript-eslint(no-redundant-type-constituents): 'never' is overridden by other types in this union type. + ,-[no-redundant-type-constituents/index.ts:10:20] + 9 | // never is redundant in unions + 10 | type T3 = string | never; + : ^^^^^ + `---- + + x typescript-eslint(no-unnecessary-boolean-literal-compare): This expression unnecessarily compares a boolean value to a boolean instead of using it directly. + ,-[no-unnecessary-boolean-literal-compare/index.ts:5:5] + 4 | + 5 | if (someCondition === true) { + : ^^^^^^^^^^^^^^^^^^^^^^ + 6 | // ... + `---- + + x typescript-eslint(no-unnecessary-boolean-literal-compare): This expression unnecessarily compares a boolean value to a boolean instead of using it directly. + ,-[no-unnecessary-boolean-literal-compare/index.ts:9:5] + 8 | + 9 | if (someCondition === false) { + : ^^^^^^^^^^^^^^^^^^^^^^^ + 10 | // ... + `---- + + x typescript-eslint(no-unnecessary-template-expression): Template literal expression is unnecessary and can be simplified. + ,-[no-unnecessary-template-expression/index.ts:10:15] + 9 | // Template with only literal expressions + 10 | const str4 = `${'Hello'} ${'world'}`; + : ^^^^^^^^^^ + `---- + + x typescript-eslint(no-unnecessary-template-expression): Template literal expression is unnecessary and can be simplified. + ,-[no-unnecessary-template-expression/index.ts:10:26] + 9 | // Template with only literal expressions + 10 | const str4 = `${'Hello'} ${'world'}`; + : ^^^^^^^^^^ + `---- + + x typescript-eslint(no-unnecessary-type-arguments): This is the default value for this type parameter, so it can be omitted. + ,-[no-unnecessary-type-arguments/index.ts:8:25] + 7 | // Unnecessary type argument - string is the default + 8 | const result = identity('hello'); + : ^^^^^^ + 9 | + `---- + + x typescript-eslint(no-unnecessary-type-assertion): This assertion is unnecessary since it does not change the type of the expression. + ,-[no-unnecessary-type-assertion/index.ts:4:19] + 3 | const str: string = 'hello'; + 4 | const redundant = str as string; // unnecessary, str is already string + : ^^^^^^^^^^^^^ + 5 | + `---- + + x typescript-eslint(no-unnecessary-type-assertion): This assertion is unnecessary since it does not change the type of the expression. + ,-[no-unnecessary-type-assertion/index.ts:9:16] + 8 | } + 9 | const result = getString() as string; // unnecessary, getString() already returns string + : ^^^^^^^^^^^^^^^^^^^^^ + 10 | + `---- + + x typescript-eslint(no-unnecessary-type-assertion): This assertion is unnecessary since it does not change the type of the expression. + ,-[no-unnecessary-type-assertion/index.ts:12:23] + 11 | const num = 42; + 12 | const alsoRedundant = num as 42; // unnecessary if TypeScript can infer literal type + : ^^^^^^^^^ + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[no-unsafe-argument/index.ts:6:3] + 5 | function takesString(str: string): void { + 6 | console.log(str.length); + : ^^^^^^^^^^^ + 7 | } + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .log on an `any` value. + ,-[no-unsafe-argument/index.ts:6:11] + 5 | function takesString(str: string): void { + 6 | console.log(str.length); + : ^^^ + 7 | } + `---- + + x typescript-eslint(no-unsafe-argument): Unsafe argument of type any assigned to a parameter of type string. + ,-[no-unsafe-argument/index.ts:9:13] + 8 | + 9 | takesString(anyValue); // unsafe + : ^^^^^^^^ + 10 | + `---- + + x typescript-eslint(no-unsafe-argument): Unsafe argument of type any assigned to a parameter of type number. + ,-[no-unsafe-argument/index.ts:12:28] + 11 | declare function takesNumber(num: number): number; + 12 | const result = takesNumber(anyValue); // unsafe + : ^^^^^^^^ + `---- + + x typescript-eslint(no-unsafe-assignment): Unsafe assignment of an any value. + ,-[no-unsafe-assignment/index.ts:5:7] + 4 | + 5 | const str: string = anyValue; // unsafe assignment + : ^^^^^^^^^^^^^^^^^^^^^^ + 6 | + `---- + + x typescript-eslint(no-unsafe-assignment): Unsafe assignment of an any value. + ,-[no-unsafe-assignment/index.ts:8:1] + 7 | let num: number; + 8 | num = anyValue; // unsafe assignment + : ^^^^^^^^^^^^^^ + 9 | + `---- + + x typescript-eslint(no-unsafe-assignment): Unsafe assignment of an any value. + ,-[no-unsafe-assignment/index.ts:11:3] + 10 | const obj = { + 11 | prop: anyValue as any, // unsafe assignment + : ^^^^^^^^^^^^^^^^^^^^^ + 12 | }; + `---- + + x typescript-eslint(no-unnecessary-type-assertion): This assertion is unnecessary since it does not change the type of the expression. + ,-[no-unsafe-assignment/index.ts:11:9] + 10 | const obj = { + 11 | prop: anyValue as any, // unsafe assignment + : ^^^^^^^^^^^^^^^ + 12 | }; + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[no-unsafe-call/index.ts:5:1] + 4 | + 5 | anyValue(); // unsafe call + : ^^^^^^^^ + 6 | + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[no-unsafe-call/index.ts:7:1] + 6 | + 7 | anyValue(1, 2, 3); // unsafe call + : ^^^^^^^^ + 8 | + `---- + + x typescript-eslint(no-unsafe-assignment): Unsafe assignment of an any value. + ,-[no-unsafe-call/index.ts:9:7] + 8 | + 9 | const result = anyValue('hello'); // unsafe call + : ^^^^^^^^^^^^^^^^^^^^^^^^^^ + 10 | + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[no-unsafe-call/index.ts:9:16] + 8 | + 9 | const result = anyValue('hello'); // unsafe call + : ^^^^^^^^ + 10 | + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[no-unsafe-call/index.ts:12:1] + 11 | // Chained unsafe calls + 12 | anyValue().then().catch(); // unsafe + : ^^^^^^^^ + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[no-unsafe-call/index.ts:12:1] + 11 | // Chained unsafe calls + 12 | anyValue().then().catch(); // unsafe + : ^^^^^^^^^^^^^^^ + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[no-unsafe-call/index.ts:12:1] + 11 | // Chained unsafe calls + 12 | anyValue().then().catch(); // unsafe + : ^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .then on an `any` value. + ,-[no-unsafe-call/index.ts:12:12] + 11 | // Chained unsafe calls + 12 | anyValue().then().catch(); // unsafe + : ^^^^ + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .catch on an `any` value. + ,-[no-unsafe-call/index.ts:12:19] + 11 | // Chained unsafe calls + 12 | anyValue().then().catch(); // unsafe + : ^^^^^ + `---- + + x typescript-eslint(no-unsafe-enum-comparison): The two values in this comparison do not have a shared enum type. + ,-[no-unsafe-enum-comparison/index.ts:14:20] + 13 | // Comparing different enums + 14 | const comparison = Status.Open === Color.Red; + : ^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .foo on an `any` value. + ,-[no-unsafe-member-access/index.ts:5:10] + 4 | + 5 | anyValue.foo; // unsafe member access + : ^^^ + 6 | + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .bar on an `any` value. + ,-[no-unsafe-member-access/index.ts:7:10] + 6 | + 7 | anyValue.bar.baz; // unsafe nested member access + : ^^^ + 8 | + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access ['key'] on an `any` value. + ,-[no-unsafe-member-access/index.ts:9:10] + 8 | + 9 | anyValue['key']; // unsafe computed member access + : ^^^^^ + 10 | + `---- + + x typescript-eslint(no-unsafe-assignment): Unsafe assignment of an any value. + ,-[no-unsafe-member-access/index.ts:11:7] + 10 | + 11 | const result = anyValue.method(); // unsafe method access + : ^^^^^^^^^^^^^^^^^^^^^^^^^^ + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[no-unsafe-member-access/index.ts:11:16] + 10 | + 11 | const result = anyValue.method(); // unsafe method access + : ^^^^^^^^^^^^^^^ + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .method on an `any` value. + ,-[no-unsafe-member-access/index.ts:11:25] + 10 | + 11 | const result = anyValue.method(); // unsafe method access + : ^^^^^^ + `---- + + x typescript-eslint(no-unsafe-return): Unsafe return of a value of type `any`. + ,-[no-unsafe-return/index.ts:6:3] + 5 | function getString(): string { + 6 | return anyValue; // unsafe return + : ^^^^^^^^^^^^^^^^ + 7 | } + `---- + + x typescript-eslint(no-unsafe-return): Unsafe return of a value of type `any`. + ,-[no-unsafe-return/index.ts:9:33] + 8 | + 9 | const getNumber = (): number => anyValue; // unsafe return + : ^^^^^^^^ + 10 | + `---- + + x typescript-eslint(no-unsafe-return): Unsafe return of a value of type `any`. + ,-[no-unsafe-return/index.ts:12:3] + 11 | function processData(): { name: string; age: number } { + 12 | return anyValue; // unsafe return + : ^^^^^^^^^^^^^^^^ + 13 | } + `---- + + x typescript-eslint(no-unsafe-assignment): Unsafe assignment of an any value. + ,-[no-unsafe-type-assertion/index.ts:5:7] + 4 | + 5 | const str = value as any; // unsafe type assertion + : ^^^^^^^^^^^^^^^^^^ + 6 | + `---- + + x typescript-eslint(no-unsafe-type-assertion): Unsafe assertion to `any` detected: consider using a more specific type to ensure safety. + ,-[no-unsafe-type-assertion/index.ts:5:13] + 4 | + 5 | const str = value as any; // unsafe type assertion + : ^^^^^^^^^^^^ + 6 | + `---- + + x typescript-eslint(no-unsafe-type-assertion): Unsafe assertion to `any` detected: consider using a more specific type to ensure safety. + ,-[no-unsafe-type-assertion/index.ts:7:13] + 6 | + 7 | const obj = value as any as string; // double assertion through any + : ^^^^^^^^^^^^ + 8 | + `---- + + x typescript-eslint(no-unsafe-type-assertion): Unsafe assertion from `any` detected: consider using type guards or a safer assertion. + ,-[no-unsafe-type-assertion/index.ts:7:13] + 6 | + 7 | const obj = value as any as string; // double assertion through any + : ^^^^^^^^^^^^^^^^^^^^^^ + 8 | + `---- + + x typescript-eslint(no-unsafe-assignment): Unsafe assignment of an any value. + ,-[no-unsafe-type-assertion/index.ts:10:9] + 9 | function processValue(input: unknown) { + 10 | const processed = input as any; // unsafe + : ^^^^^^^^^^^^^^^^^^^^^^^^ + 11 | return processed.someProperty; + `---- + + x typescript-eslint(no-unsafe-type-assertion): Unsafe assertion to `any` detected: consider using a more specific type to ensure safety. + ,-[no-unsafe-type-assertion/index.ts:10:21] + 9 | function processValue(input: unknown) { + 10 | const processed = input as any; // unsafe + : ^^^^^^^^^^^^ + 11 | return processed.someProperty; + `---- + + x typescript-eslint(no-unsafe-return): Unsafe return of a value of type `any`. + ,-[no-unsafe-type-assertion/index.ts:11:3] + 10 | const processed = input as any; // unsafe + 11 | return processed.someProperty; + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 12 | } + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .someProperty on an `any` value. + ,-[no-unsafe-type-assertion/index.ts:11:20] + 10 | const processed = input as any; // unsafe + 11 | return processed.someProperty; + : ^^^^^^^^^^^^ + 12 | } + `---- + + x typescript-eslint(no-unsafe-unary-minus): Argument of unary negation should be assignable to number | bigint but is null instead. + ,-[no-unsafe-unary-minus/index.ts:4:17] + 3 | declare const value: any; + 4 | const result1 = -value; // unsafe on any + : ^^^^^^ + 5 | + `---- + + x typescript-eslint(no-unsafe-unary-minus): Argument of unary negation should be assignable to number | bigint but is string instead. + ,-[no-unsafe-unary-minus/index.ts:7:17] + 6 | declare const str: string; + 7 | const result2 = -str; // unsafe on string + : ^^^^ + 8 | + `---- + + x typescript-eslint(no-unsafe-unary-minus): Argument of unary negation should be assignable to number | bigint but is false instead. + ,-[no-unsafe-unary-minus/index.ts:10:17] + 9 | declare const bool: boolean; + 10 | const result3 = -bool; // unsafe on boolean + : ^^^^^ + 11 | + `---- + + x typescript-eslint(no-unsafe-unary-minus): Argument of unary negation should be assignable to number | bigint but is object instead. + ,-[no-unsafe-unary-minus/index.ts:13:17] + 12 | declare const obj: object; + 13 | const result4 = -obj; // unsafe on object + : ^^^^ + `---- + + x typescript-eslint(no-unsafe-type-assertion): Unsafe type assertion: type 'string' is more narrow than the original type. + ,-[non-nullable-type-assertion-style/index.ts:6:17] + 5 | // Type assertion when non-null assertion would be clearer + 6 | const result1 = value as string; + : ^^^^^^^^^^^^^^^ + 7 | + `---- + + x typescript-eslint(non-nullable-type-assertion-style): Use a ! assertion to more succinctly remove null and undefined from the type. + ,-[non-nullable-type-assertion-style/index.ts:6:17] + 5 | // Type assertion when non-null assertion would be clearer + 6 | const result1 = value as string; + : ^^^^^^^^^^^^^^^ + 7 | + `---- + + x typescript-eslint(no-unsafe-type-assertion): Unsafe type assertion: type 'number' is more narrow than the original type. + ,-[non-nullable-type-assertion-style/index.ts:9:17] + 8 | declare const maybe: number | undefined; + 9 | const result2 = maybe as number; + : ^^^^^^^^^^^^^^^ + `---- + + x typescript-eslint(non-nullable-type-assertion-style): Use a ! assertion to more succinctly remove null and undefined from the type. + ,-[non-nullable-type-assertion-style/index.ts:9:17] + 8 | declare const maybe: number | undefined; + 9 | const result2 = maybe as number; + : ^^^^^^^^^^^^^^^ + `---- + x ]8;;https://oxc.rs/docs/guide/usage/linter/rules/eslint/no-debugger.html\eslint(no-debugger)]8;;\: `debugger` statement is not allowed ,-[non-tsgolint.ts:1:1] 1 | debugger; @@ -109,8 +936,588 @@ working directory: fixtures/tsgolint `---- help: Remove the debugger statement -Found 5 warnings and 7 errors. -Finished in ms on 4 files using 1 threads. + x typescript-eslint(only-throw-error): Expected an error object to be thrown. + ,-[only-throw-error/index.ts:3:7] + 2 | + 3 | throw 'error'; // throwing string + : ^^^^^^^ + 4 | + `---- + + x typescript-eslint(only-throw-error): Expected an error object to be thrown. + ,-[only-throw-error/index.ts:5:7] + 4 | + 5 | throw 42; // throwing number + : ^^ + 6 | + `---- + + x typescript-eslint(only-throw-error): Expected an error object to be thrown. + ,-[only-throw-error/index.ts:7:7] + 6 | + 7 | throw true; // throwing boolean + : ^^^^ + 8 | + `---- + + x typescript-eslint(only-throw-error): Expected an error object to be thrown. + ,-[only-throw-error/index.ts:9:7] + 8 | + 9 | throw { message: 'error' }; // throwing plain object + : ^^^^^^^^^^^^^^^^^^^^ + 10 | + `---- + + x typescript-eslint(only-throw-error): Expected an error object to be thrown. + ,-[only-throw-error/index.ts:11:7] + 10 | + 11 | throw null; // throwing null + : ^^^^ + `---- + + x typescript-eslint(prefer-promise-reject-errors): Expected the Promise rejection reason to be an Error. + ,-[prefer-promise-reject-errors/index.ts:3:1] + 2 | + 3 | Promise.reject('error'); // rejecting with string + : ^^^^^^^^^^^^^^^^^^^^^^^ + 4 | + `---- + + x typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` + | operator. + ,-[prefer-promise-reject-errors/index.ts:3:1] + 2 | + 3 | Promise.reject('error'); // rejecting with string + : ^^^^^^^^^^^^^^^^^^^^^^^^ + 4 | + `---- + + x typescript-eslint(prefer-promise-reject-errors): Expected the Promise rejection reason to be an Error. + ,-[prefer-promise-reject-errors/index.ts:5:1] + 4 | + 5 | Promise.reject(42); // rejecting with number + : ^^^^^^^^^^^^^^^^^^ + 6 | + `---- + + x typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` + | operator. + ,-[prefer-promise-reject-errors/index.ts:5:1] + 4 | + 5 | Promise.reject(42); // rejecting with number + : ^^^^^^^^^^^^^^^^^^^ + 6 | + `---- + + x typescript-eslint(prefer-promise-reject-errors): Expected the Promise rejection reason to be an Error. + ,-[prefer-promise-reject-errors/index.ts:7:1] + 6 | + 7 | Promise.reject(true); // rejecting with boolean + : ^^^^^^^^^^^^^^^^^^^^ + 8 | + `---- + + x typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` + | operator. + ,-[prefer-promise-reject-errors/index.ts:7:1] + 6 | + 7 | Promise.reject(true); // rejecting with boolean + : ^^^^^^^^^^^^^^^^^^^^^ + 8 | + `---- + + x typescript-eslint(prefer-promise-reject-errors): Expected the Promise rejection reason to be an Error. + ,-[prefer-promise-reject-errors/index.ts:9:1] + 8 | + 9 | Promise.reject({ message: 'error' }); // rejecting with plain object + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 10 | + `---- + + x typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` + | operator. + ,-[prefer-promise-reject-errors/index.ts:9:1] + 8 | + 9 | Promise.reject({ message: 'error' }); // rejecting with plain object + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 10 | + `---- + + x typescript-eslint(prefer-promise-reject-errors): Expected the Promise rejection reason to be an Error. + ,-[prefer-promise-reject-errors/index.ts:11:1] + 10 | + 11 | Promise.reject(null); // rejecting with null + : ^^^^^^^^^^^^^^^^^^^^ + `---- + + x typescript-eslint(no-floating-promises): Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` + | operator. + ,-[prefer-promise-reject-errors/index.ts:11:1] + 10 | + 11 | Promise.reject(null); // rejecting with null + : ^^^^^^^^^^^^^^^^^^^^^ + `---- + + x typescript-eslint(no-unnecessary-type-assertion): This assertion is unnecessary since it does not change the type of the expression. + ,-[prefer-reduce-type-parameter/index.ts:6:13] + 5 | // Casting the result + 6 | const sum = numbers.reduce((acc, val) => acc + val, 0) as number; + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 7 | + `---- + + x typescript-eslint(prefer-reduce-type-parameter): Unnecessary assertion: Array#reduce accepts a type parameter for the default value. + ,-[prefer-reduce-type-parameter/index.ts:12:4] + 11 | return acc; + 12 | }, [] as string[]); + : ^^^^^^^^^^^^^^ + `---- + + x typescript-eslint(prefer-return-this-type): Use `this` type instead. + ,-[prefer-return-this-type/index.ts:6:28] + 5 | + 6 | setValue(value: string): Builder { // Should return 'this' + : ^^^^^^^ + 7 | this.value = value; + `---- + + x typescript-eslint(promise-function-async): Functions that return promises must be async. + ,-[promise-function-async/index.ts:4:1] + 3 | // Function returning Promise without async + 4 | ,-> function fetchData(): Promise { + 5 | | return fetch('/api/data').then(res => res.text()); + 6 | `-> } + 7 | + `---- + + x typescript-eslint(no-unsafe-return): Unsafe return of a value of type `any`. + ,-[promise-function-async/index.ts:5:3] + 4 | function fetchData(): Promise { + 5 | return fetch('/api/data').then(res => res.text()); + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 6 | } + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[promise-function-async/index.ts:5:10] + 4 | function fetchData(): Promise { + 5 | return fetch('/api/data').then(res => res.text()); + : ^^^^^ + 6 | } + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[promise-function-async/index.ts:5:10] + 4 | function fetchData(): Promise { + 5 | return fetch('/api/data').then(res => res.text()); + : ^^^^^^^^^^^^^^^^^^^^^^^ + 6 | } + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .then on an `any` value. + ,-[promise-function-async/index.ts:5:29] + 4 | function fetchData(): Promise { + 5 | return fetch('/api/data').then(res => res.text()); + : ^^^^ + 6 | } + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[promise-function-async/index.ts:5:41] + 4 | function fetchData(): Promise { + 5 | return fetch('/api/data').then(res => res.text()); + : ^^^^^^^^ + 6 | } + `---- + + x typescript-eslint(no-unsafe-return): Unsafe return of a value of type `any`. + ,-[promise-function-async/index.ts:5:41] + 4 | function fetchData(): Promise { + 5 | return fetch('/api/data').then(res => res.text()); + : ^^^^^^^^^^ + 6 | } + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .text on an `any` value. + ,-[promise-function-async/index.ts:5:45] + 4 | function fetchData(): Promise { + 5 | return fetch('/api/data').then(res => res.text()); + : ^^^^ + 6 | } + `---- + + x typescript-eslint(promise-function-async): Functions that return promises must be async. + ,-[promise-function-async/index.ts:10:3] + 9 | class DataService { + 10 | ,-> getData(): Promise { + 11 | | return fetch('/api/data').then(res => res.json()); + 12 | `-> } + 13 | } + `---- + + x typescript-eslint(no-unsafe-return): Unsafe return of a value of type `any`. + ,-[promise-function-async/index.ts:11:5] + 10 | getData(): Promise { + 11 | return fetch('/api/data').then(res => res.json()); + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 12 | } + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[promise-function-async/index.ts:11:12] + 10 | getData(): Promise { + 11 | return fetch('/api/data').then(res => res.json()); + : ^^^^^ + 12 | } + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[promise-function-async/index.ts:11:12] + 10 | getData(): Promise { + 11 | return fetch('/api/data').then(res => res.json()); + : ^^^^^^^^^^^^^^^^^^^^^^^ + 12 | } + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .then on an `any` value. + ,-[promise-function-async/index.ts:11:31] + 10 | getData(): Promise { + 11 | return fetch('/api/data').then(res => res.json()); + : ^^^^ + 12 | } + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[promise-function-async/index.ts:11:43] + 10 | getData(): Promise { + 11 | return fetch('/api/data').then(res => res.json()); + : ^^^^^^^^ + 12 | } + `---- + + x typescript-eslint(no-unsafe-return): Unsafe return of a value of type `any`. + ,-[promise-function-async/index.ts:11:43] + 10 | getData(): Promise { + 11 | return fetch('/api/data').then(res => res.json()); + : ^^^^^^^^^^ + 12 | } + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .json on an `any` value. + ,-[promise-function-async/index.ts:11:47] + 10 | getData(): Promise { + 11 | return fetch('/api/data').then(res => res.json()); + : ^^^^ + 12 | } + `---- + + x typescript-eslint(related-getter-setter-pairs): `get()` type should be assignable to its equivalent `set()` type. + ,-[related-getter-setter-pairs/index.ts:7:16] + 6 | // Getter and setter with incompatible types + 7 | get value(): string { + : ^^^^^^ + 8 | return this._value.toString(); + `---- + + x typescript-eslint(require-array-sort-compare): Require 'compare' argument. + ,-[require-array-sort-compare/index.ts:4:1] + 3 | const numbers = [3, 1, 4, 1, 5]; + 4 | numbers.sort(); // Lexicographic sort, not numeric + : ^^^^^^^^^^^^^^ + 5 | + `---- + + x typescript-eslint(require-array-sort-compare): Require 'compare' argument. + ,-[require-array-sort-compare/index.ts:9:1] + 8 | + 9 | [3, 1, 4].sort(); // Will sort as strings: ['1', '3', '4'] + : ^^^^^^^^^^^^^^^^ + `---- + + x typescript-eslint(require-await): Function has no 'await' expression. + ,-[require-await/index.ts:4:1] + 3 | // Async function without await + 4 | ,-> async function fetchData() { + 5 | | return fetch('/api/data'); + 6 | `-> } + 7 | + `---- + + x typescript-eslint(no-unsafe-return): Unsafe return of a value of type `any`. + ,-[require-await/index.ts:5:3] + 4 | async function fetchData() { + 5 | return fetch('/api/data'); + : ^^^^^^^^^^^^^^^^^^^^^^^^^^ + 6 | } + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[require-await/index.ts:5:10] + 4 | async function fetchData() { + 5 | return fetch('/api/data'); + : ^^^^^ + 6 | } + `---- + + x typescript-eslint(require-await): Function has no 'await' expression. + ,-[require-await/index.ts:9:21] + 8 | // Async arrow function without await + 9 | ,-> const processData = async () => { + 10 | | return someData.map(x => x * 2); + 11 | `-> }; + `---- + + x typescript-eslint(no-unsafe-return): Unsafe return of a value of type `any`. + ,-[require-await/index.ts:10:3] + 9 | const processData = async () => { + 10 | return someData.map(x => x * 2); + : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 11 | }; + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[require-await/index.ts:10:10] + 9 | const processData = async () => { + 10 | return someData.map(x => x * 2); + : ^^^^^^^^^^^^ + 11 | }; + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .map on an `any` value. + ,-[require-await/index.ts:10:19] + 9 | const processData = async () => { + 10 | return someData.map(x => x * 2); + : ^^^ + 11 | }; + `---- + + x typescript-eslint(no-unsafe-assignment): Unsafe assignment of an any value. + ,-[restrict-plus-operands/index.ts:1:5] + 1 | let foo = 1n + 1; + : ^^^^^^^^^^^^ + 2 | let fn = (a: string, b: never) => a + b; + `---- + + x typescript-eslint(restrict-plus-operands): Numeric '+' operations must either be both bigints or both numbers. Got `bigint` + `number`. + ,-[restrict-plus-operands/index.ts:1:11] + 1 | let foo = 1n + 1; + : ^^^^^^ + 2 | let fn = (a: string, b: never) => a + b; + `---- + + x typescript-eslint(restrict-plus-operands): Invalid operand for a '+' operation. Operands must each be a number or string, allowing a string + any of: `any`, `boolean`, `null`, `RegExp`, + | `undefined`. Got `never`. + ,-[restrict-plus-operands/index.ts:2:39] + 1 | let foo = 1n + 1; + 2 | let fn = (a: string, b: never) => a + b; + : ^ + `---- + + x typescript-eslint(no-base-to-string): 'obj' always use Object's default stringification format ('[object Object]') when stringified. + ,-[restrict-template-expressions/index.ts:9:24] + 8 | // Objects become "[object Object]" + 9 | const str1 = `Value: ${obj}`; + : ^^^ + 10 | + `---- + + x typescript-eslint(restrict-template-expressions): Invalid type "object" of template literal expression. + ,-[restrict-template-expressions/index.ts:9:24] + 8 | // Objects become "[object Object]" + 9 | const str1 = `Value: ${obj}`; + : ^^^ + 10 | + `---- + + x typescript-eslint(restrict-template-expressions): Invalid type "symbol" of template literal expression. + ,-[restrict-template-expressions/index.ts:12:25] + 11 | // Symbols might not be what you expect + 12 | const str2 = `Symbol: ${sym}`; + : ^^^ + 13 | + `---- + + x typescript-eslint(restrict-template-expressions): Invalid type "() => void" of template literal expression. + ,-[restrict-template-expressions/index.ts:15:27] + 14 | // Functions become their string representation + 15 | const str3 = `Function: ${fn}`; + : ^^ + 16 | + `---- + + x typescript-eslint(restrict-template-expressions): Invalid type "number[]" of template literal expression. + ,-[restrict-template-expressions/index.ts:18:24] + 17 | // Arrays of unknown might be unsafe + 18 | const str4 = `Array: ${arr}`; + : ^^^ + `---- + + x typescript-eslint(no-unsafe-return): Unsafe return of a value of type `Promise`. + ,-[return-await/index.ts:12:5] + 11 | // Should be: return await fetchData(); + 12 | return fetchData(); // Missing await in try block + : ^^^^^^^^^^^^^^^^^^^ + 13 | } catch (error) { + `---- + + x typescript-eslint(return-await): Returning an awaited promise is required in this context. + ,-[return-await/index.ts:12:12] + 11 | // Should be: return await fetchData(); + 12 | return fetchData(); // Missing await in try block + : ^^^^^^^^^^^ + 13 | } catch (error) { + `---- + + x typescript-eslint(return-await): Returning an awaited promise is required in this context. + ,-[return-await/index.ts:21:12] + 20 | try { + 21 | return handleAsync(); // Should use await + : ^^^^^^^^^^^^^ + 22 | } catch (error) { + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[return-await/index.ts:23:5] + 22 | } catch (error) { + 23 | console.error(error); + : ^^^^^^^^^^^^^ + 24 | throw error; + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .error on an `any` value. + ,-[return-await/index.ts:23:13] + 22 | } catch (error) { + 23 | console.error(error); + : ^^^^^ + 24 | throw error; + `---- + + x typescript-eslint(switch-exhaustiveness-check): Switch is not exhaustive + ,-[switch-exhaustiveness-check/index.ts:6:11] + 5 | function handleStatus(status: Status) { + 6 | switch (status) { + : ^^^^^^ + 7 | case 'pending': + `---- + + x typescript-eslint(no-unsafe-enum-comparison): The case statement does not have a shared enum type with the switch predicate. + ,-[switch-exhaustiveness-check/index.ts:7:5] + 6 | switch (status) { + 7 | ,-> case 'pending': + 8 | `-> return 'Waiting for approval'; + 9 | case 'approved': + `---- + + x typescript-eslint(no-unsafe-enum-comparison): The case statement does not have a shared enum type with the switch predicate. + ,-[switch-exhaustiveness-check/index.ts:9:5] + 8 | return 'Waiting for approval'; + 9 | ,-> case 'approved': + 10 | `-> return 'Request approved'; + 11 | // Missing 'rejected' case + `---- + + x typescript-eslint(unbound-method): Avoid referencing unbound methods which may cause unintentional scoping of `this`. + | If your function does not access `this`, you can annotate it with `this: void`, or consider using an arrow function instead. + ,-[unbound-method/index.ts:19:19] + 18 | // Unbound method - loses 'this' context + 19 | const addMethod = calc.add; + : ^^^^^^^^ + 20 | addMethod(5); // Error: 'this' is undefined + `---- + + x typescript-eslint(unbound-method): Avoid referencing unbound methods which may cause unintentional scoping of `this`. + | If your function does not access `this`, you can annotate it with `this: void`, or consider using an arrow function instead. + ,-[unbound-method/index.ts:23:18] + 22 | // Array method callback loses context + 23 | const getValue = calc.getValue; + : ^^^^^^^^^^^^^ + 24 | [1, 2, 3].map(getValue); // Error: each call loses 'this' + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[unbound-method/index.ts:27:1] + 26 | // Unbound method in setTimeout + 27 | setTimeout(calc.add, 1000, 10); // Error: 'this' context lost + : ^^^^^^^^^^ + 28 | + `---- + + x typescript-eslint(unbound-method): Avoid referencing unbound methods which may cause unintentional scoping of `this`. + | If your function does not access `this`, you can annotate it with `this: void`, or consider using an arrow function instead. + ,-[unbound-method/index.ts:27:12] + 26 | // Unbound method in setTimeout + 27 | setTimeout(calc.add, 1000, 10); // Error: 'this' context lost + : ^^^^^^^^ + 28 | + `---- + + x typescript-eslint(unbound-method): Avoid referencing unbound methods which may cause unintentional scoping of `this`. + | If your function does not access `this`, you can annotate it with `this: void`, or consider using an arrow function instead. + ,-[unbound-method/index.ts:30:9] + 29 | // Class method destructuring + 30 | const { getValue: getVal } = calc; + : ^^^^^^^^ + 31 | getVal(); // Error: 'this' context lost + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[use-unknown-in-catch-callback-variable/index.ts:7:3] + 6 | } catch (error: any) { // Should be: error: unknown + 7 | console.log(error.message); + : ^^^^^^^^^^^ + 8 | } + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .log on an `any` value. + ,-[use-unknown-in-catch-callback-variable/index.ts:7:11] + 6 | } catch (error: any) { // Should be: error: unknown + 7 | console.log(error.message); + : ^^^ + 8 | } + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .message on an `any` value. + ,-[use-unknown-in-catch-callback-variable/index.ts:7:21] + 6 | } catch (error: any) { // Should be: error: unknown + 7 | console.log(error.message); + : ^^^^^^^ + 8 | } + `---- + + x typescript-eslint(use-unknown-in-catch-callback-variable): Prefer the safe `: unknown` for a `catch` callback variable. + ,-[use-unknown-in-catch-callback-variable/index.ts:18:16] + 17 | // Promise catch with explicit any + 18 | promise.catch((error: any) => { // Should be: error: unknown + : ^^^^^^^^^^ + 19 | console.error(error.message); + `---- + + x typescript-eslint(no-unsafe-call): Unsafe call of a(n) `any` typed value. + ,-[use-unknown-in-catch-callback-variable/index.ts:19:3] + 18 | promise.catch((error: any) => { // Should be: error: unknown + 19 | console.error(error.message); + : ^^^^^^^^^^^^^ + 20 | }); + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .error on an `any` value. + ,-[use-unknown-in-catch-callback-variable/index.ts:19:11] + 18 | promise.catch((error: any) => { // Should be: error: unknown + 19 | console.error(error.message); + : ^^^^^ + 20 | }); + `---- + + x typescript-eslint(no-unsafe-member-access): Unsafe member access .message on an `any` value. + ,-[use-unknown-in-catch-callback-variable/index.ts:19:23] + 18 | promise.catch((error: any) => { // Should be: error: unknown + 19 | console.error(error.message); + : ^^^^^^^ + 20 | }); + `---- + +Found 5 warnings and 184 errors. +Finished in ms on 42 files using 1 threads. ---------- CLI result: LintFoundErrors ---------- diff --git a/crates/oxc_linter/src/rules.rs b/crates/oxc_linter/src/rules.rs index 76e53223eb2eb..62f7aeab02eb9 100644 --- a/crates/oxc_linter/src/rules.rs +++ b/crates/oxc_linter/src/rules.rs @@ -192,6 +192,7 @@ mod eslint { mod typescript { pub mod adjacent_overload_signatures; pub mod array_type; + pub mod await_thenable; pub mod ban_ts_comment; pub mod ban_tslint_comment; pub mod ban_types; @@ -201,8 +202,12 @@ mod typescript { pub mod consistent_type_imports; pub mod explicit_function_return_type; pub mod explicit_module_boundary_types; + pub mod no_array_delete; + pub mod no_base_to_string; pub mod no_confusing_non_null_assertion; + pub mod no_confusing_void_expression; pub mod no_duplicate_enum_values; + pub mod no_duplicate_type_constituents; pub mod no_dynamic_delete; pub mod no_empty_interface; pub mod no_empty_object_type; @@ -210,32 +215,64 @@ mod typescript { pub mod no_extra_non_null_assertion; pub mod no_extraneous_class; pub mod no_floating_promises; + pub mod no_for_in_array; + pub mod no_implied_eval; pub mod no_import_type_side_effects; pub mod no_inferrable_types; + pub mod no_meaningless_void_operator; pub mod no_misused_new; pub mod no_misused_promises; + pub mod no_misused_spread; + pub mod no_mixed_enums; pub mod no_namespace; pub mod no_non_null_asserted_nullish_coalescing; pub mod no_non_null_asserted_optional_chain; pub mod no_non_null_assertion; + pub mod no_redundant_type_constituents; pub mod no_require_imports; pub mod no_this_alias; + pub mod no_unnecessary_boolean_literal_compare; pub mod no_unnecessary_parameter_property_assignment; + pub mod no_unnecessary_template_expression; + pub mod no_unnecessary_type_arguments; + pub mod no_unnecessary_type_assertion; pub mod no_unnecessary_type_constraint; + pub mod no_unsafe_argument; + pub mod no_unsafe_assignment; + pub mod no_unsafe_call; pub mod no_unsafe_declaration_merging; + pub mod no_unsafe_enum_comparison; pub mod no_unsafe_function_type; - + pub mod no_unsafe_member_access; + pub mod no_unsafe_return; + pub mod no_unsafe_type_assertion; + pub mod no_unsafe_unary_minus; pub mod no_useless_empty_export; pub mod no_var_requires; pub mod no_wrapper_object_types; + pub mod non_nullable_type_assertion_style; + pub mod only_throw_error; pub mod prefer_as_const; pub mod prefer_enum_initializers; pub mod prefer_for_of; pub mod prefer_function_type; pub mod prefer_literal_enum_member; pub mod prefer_namespace_keyword; + pub mod prefer_promise_reject_errors; + pub mod prefer_reduce_type_parameter; + pub mod prefer_return_this_type; pub mod prefer_ts_expect_error; + pub mod promise_function_async; + pub mod related_getter_setter_pairs; + pub mod require_array_sort_compare; + pub mod require_await; + pub mod restrict_plus_operands; + pub mod restrict_template_expressions; + pub mod return_await; + pub mod switch_exhaustiveness_check; pub mod triple_slash_reference; + pub mod unbound_method; + pub mod use_unknown_in_catch_callback_variable; } mod jest { @@ -958,6 +995,7 @@ oxc_macros::declare_all_lint_rules! { react_perf::jsx_no_new_object_as_prop, typescript::adjacent_overload_signatures, typescript::array_type, + typescript::await_thenable, typescript::ban_ts_comment, typescript::ban_tslint_comment, typescript::ban_types, @@ -970,37 +1008,74 @@ oxc_macros::declare_all_lint_rules! { typescript::no_misused_promises, typescript::no_floating_promises, typescript::no_inferrable_types, + typescript::no_array_delete, + typescript::no_base_to_string, typescript::no_confusing_non_null_assertion, + typescript::no_confusing_void_expression, typescript::no_duplicate_enum_values, + typescript::no_duplicate_type_constituents, typescript::no_dynamic_delete, typescript::no_empty_interface, typescript::no_empty_object_type, typescript::no_explicit_any, typescript::no_extra_non_null_assertion, typescript::no_extraneous_class, + typescript::no_for_in_array, + typescript::no_implied_eval, typescript::no_import_type_side_effects, + typescript::no_meaningless_void_operator, typescript::no_misused_new, + typescript::no_misused_spread, + typescript::no_mixed_enums, typescript::no_namespace, typescript::no_non_null_asserted_nullish_coalescing, typescript::no_non_null_asserted_optional_chain, typescript::no_non_null_assertion, + typescript::no_redundant_type_constituents, typescript::no_require_imports, typescript::no_this_alias, + typescript::no_unnecessary_boolean_literal_compare, typescript::no_unnecessary_parameter_property_assignment, + typescript::no_unnecessary_template_expression, + typescript::no_unnecessary_type_arguments, + typescript::no_unnecessary_type_assertion, typescript::no_unnecessary_type_constraint, + typescript::no_unsafe_argument, + typescript::no_unsafe_assignment, + typescript::no_unsafe_call, typescript::no_unsafe_declaration_merging, + typescript::no_unsafe_enum_comparison, typescript::no_unsafe_function_type, + typescript::no_unsafe_member_access, + typescript::no_unsafe_return, + typescript::no_unsafe_type_assertion, + typescript::no_unsafe_unary_minus, typescript::no_useless_empty_export, typescript::no_var_requires, typescript::no_wrapper_object_types, + typescript::non_nullable_type_assertion_style, + typescript::only_throw_error, typescript::prefer_as_const, typescript::prefer_enum_initializers, typescript::prefer_for_of, typescript::prefer_function_type, typescript::prefer_literal_enum_member, typescript::prefer_namespace_keyword, + typescript::prefer_promise_reject_errors, + typescript::prefer_reduce_type_parameter, + typescript::prefer_return_this_type, typescript::prefer_ts_expect_error, + typescript::promise_function_async, + typescript::related_getter_setter_pairs, + typescript::require_array_sort_compare, + typescript::require_await, + typescript::restrict_plus_operands, + typescript::restrict_template_expressions, + typescript::return_await, + typescript::switch_exhaustiveness_check, typescript::triple_slash_reference, + typescript::unbound_method, + typescript::use_unknown_in_catch_callback_variable, unicorn::catch_error_name, unicorn::consistent_assert, unicorn::consistent_date_clone, diff --git a/crates/oxc_linter/src/rules/typescript/await_thenable.rs b/crates/oxc_linter/src/rules/typescript/await_thenable.rs new file mode 100644 index 0000000000000..67d7c5247bf6f --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/await_thenable.rs @@ -0,0 +1,55 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct AwaitThenable; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule disallows awaiting a value that is not a Thenable. + /// + /// ### Why is this bad? + /// + /// While it is valid JavaScript to await a non-Promise-like value (it will resolve immediately), this practice can be confusing for readers who are not aware of this behavior. It can also be a sign of a programmer error, such as forgetting to add parentheses to call a function that returns a Promise. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// await 12; + /// await (() => {}); + /// + /// // non-Promise values + /// await Math.random; + /// await { then() {} }; + /// + /// // this is not a Promise - it's a function that returns a Promise + /// declare const getPromise: () => Promise; + /// await getPromise; + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// await Promise.resolve('value'); + /// await Promise.reject(new Error()); + /// + /// // Promise-like values + /// await { + /// then(onfulfilled, onrejected) { + /// onfulfilled('value'); + /// }, + /// }; + /// + /// // this is a Promise - produced by calling a function + /// declare const getPromise: () => Promise; + /// await getPromise(); + /// ``` + AwaitThenable(tsgolint), + typescript, + correctness, + pending, +); + +impl Rule for AwaitThenable {} diff --git a/crates/oxc_linter/src/rules/typescript/no_array_delete.rs b/crates/oxc_linter/src/rules/typescript/no_array_delete.rs new file mode 100644 index 0000000000000..4b122d95cba76 --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/no_array_delete.rs @@ -0,0 +1,43 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct NoArrayDelete; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule disallows using the delete operator on array values. + /// + /// ### Why is this bad? + /// + /// When using the delete operator on an array, the element is not actually removed, but instead the array slot is turned into undefined. This is usually not the intended behavior. Instead, you should use methods like Array.prototype.splice() to properly remove elements from an array. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// declare const arr: number[]; + /// delete arr[0]; + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// declare const arr: number[]; + /// arr.splice(0, 1); + /// + /// // or with a filter + /// const filteredArr = arr.filter((_, index) => index !== 0); + /// + /// // delete on object is allowed + /// declare const obj: { a?: number }; + /// delete obj.a; + /// ``` + NoArrayDelete(tsgolint), + typescript, + correctness, + pending, +); + +impl Rule for NoArrayDelete {} diff --git a/crates/oxc_linter/src/rules/typescript/no_base_to_string.rs b/crates/oxc_linter/src/rules/typescript/no_base_to_string.rs new file mode 100644 index 0000000000000..7219135ee7170 --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/no_base_to_string.rs @@ -0,0 +1,54 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct NoBaseToString; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule requires toString() and toLocaleString() calls to only be called on objects which provide useful information when stringified. + /// + /// ### Why is this bad? + /// + /// JavaScript's toString() method returns '[object Object]' on plain objects, which is not useful information. This rule prevents toString() and toLocaleString() from being called on objects that return less useful strings. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// // These will evaluate to '[object Object]' + /// ({}).toString(); + /// ({foo: 'bar'}).toString(); + /// ({foo: 'bar'}).toLocaleString(); + /// + /// // This will evaluate to 'Symbol()' + /// Symbol('foo').toString(); + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// const someString = 'Hello world'; + /// someString.toString(); + /// + /// const someNumber = 42; + /// someNumber.toString(); + /// + /// const someBoolean = true; + /// someBoolean.toString(); + /// + /// class CustomToString { + /// toString() { + /// return 'CustomToString'; + /// } + /// } + /// new CustomToString().toString(); + /// ``` + NoBaseToString(tsgolint), + typescript, + correctness, + pending, +); + +impl Rule for NoBaseToString {} diff --git a/crates/oxc_linter/src/rules/typescript/no_confusing_void_expression.rs b/crates/oxc_linter/src/rules/typescript/no_confusing_void_expression.rs new file mode 100644 index 0000000000000..c1d06948b8d3d --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/no_confusing_void_expression.rs @@ -0,0 +1,58 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct NoConfusingVoidExpression; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule forbids using void expressions in confusing locations such as arrow function returns. + /// + /// ### Why is this bad? + /// + /// The void operator is useful when you want to execute an expression while evaluating to undefined. However, it can be confusing when used in places where the return value is meaningful, particularly in arrow functions and conditional expressions. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// // arrow function returning void expression + /// const foo = () => void bar(); + /// + /// // conditional expression + /// const result = condition ? void foo() : bar(); + /// + /// // void in conditional + /// if (void foo()) { + /// // ... + /// } + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// // proper use of void + /// void foo(); + /// + /// // explicit return statement + /// const foo = () => { + /// bar(); + /// return; + /// }; + /// + /// // statement expression + /// foo(); + /// + /// // IIFE with void + /// void (function() { + /// console.log('immediately invoked'); + /// })(); + /// ``` + NoConfusingVoidExpression(tsgolint), + typescript, + correctness, + pending, +); + +impl Rule for NoConfusingVoidExpression {} diff --git a/crates/oxc_linter/src/rules/typescript/no_duplicate_type_constituents.rs b/crates/oxc_linter/src/rules/typescript/no_duplicate_type_constituents.rs new file mode 100644 index 0000000000000..577fc1fdb535b --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/no_duplicate_type_constituents.rs @@ -0,0 +1,56 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct NoDuplicateTypeConstituents; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule disallows duplicate constituents of union or intersection types. + /// + /// ### Why is this bad? + /// + /// Duplicate constituents in union and intersection types serve no purpose and can make code harder to read. They are likely a mistake. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// type T1 = 'A' | 'A'; + /// + /// type T2 = A | A | B; + /// + /// type T3 = { a: string } & { a: string }; + /// + /// type T4 = [A, A]; + /// + /// type T5 = + /// | 'foo' + /// | 'bar' + /// | 'foo'; + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// type T1 = 'A' | 'B'; + /// + /// type T2 = A | B | C; + /// + /// type T3 = { a: string } & { b: string }; + /// + /// type T4 = [A, B]; + /// + /// type T5 = + /// | 'foo' + /// | 'bar' + /// | 'baz'; + /// ``` + NoDuplicateTypeConstituents(tsgolint), + typescript, + correctness, + pending, +); + +impl Rule for NoDuplicateTypeConstituents {} diff --git a/crates/oxc_linter/src/rules/typescript/no_floating_promises.rs b/crates/oxc_linter/src/rules/typescript/no_floating_promises.rs index c634513868206..58196443e389b 100644 --- a/crates/oxc_linter/src/rules/typescript/no_floating_promises.rs +++ b/crates/oxc_linter/src/rules/typescript/no_floating_promises.rs @@ -72,7 +72,7 @@ declare_oxc_lint!( /// ``` NoFloatingPromises(tsgolint), typescript, - suspicious, + correctness, pending, ); diff --git a/crates/oxc_linter/src/rules/typescript/no_for_in_array.rs b/crates/oxc_linter/src/rules/typescript/no_for_in_array.rs new file mode 100644 index 0000000000000..fd290640295af --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/no_for_in_array.rs @@ -0,0 +1,63 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct NoForInArray; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule disallows iterating over an array with a for-in loop. + /// + /// ### Why is this bad? + /// + /// A for-in loop iterates over the enumerable properties of an object, which includes the array indices, but also includes any enumerable properties added to the array prototype or the array instance. This is almost never what you want when iterating over an array. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// const arr = [1, 2, 3]; + /// + /// for (const i in arr) { + /// console.log(arr[i]); + /// } + /// + /// for (const i in arr) { + /// console.log(i, arr[i]); + /// } + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// const arr = [1, 2, 3]; + /// + /// // Use for-of to iterate over array values + /// for (const value of arr) { + /// console.log(value); + /// } + /// + /// // Use regular for loop with index + /// for (let i = 0; i < arr.length; i++) { + /// console.log(i, arr[i]); + /// } + /// + /// // Use forEach + /// arr.forEach((value, index) => { + /// console.log(index, value); + /// }); + /// + /// // for-in is fine for objects + /// const obj = { a: 1, b: 2 }; + /// for (const key in obj) { + /// console.log(key, obj[key]); + /// } + /// ``` + NoForInArray(tsgolint), + typescript, + correctness, + pending, +); + +impl Rule for NoForInArray {} diff --git a/crates/oxc_linter/src/rules/typescript/no_implied_eval.rs b/crates/oxc_linter/src/rules/typescript/no_implied_eval.rs new file mode 100644 index 0000000000000..9345a3b73d1d6 --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/no_implied_eval.rs @@ -0,0 +1,56 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct NoImpliedEval; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule disallows the use of eval-like methods. + /// + /// ### Why is this bad? + /// + /// It's considered a good practice to avoid using eval() in JavaScript. There are security and performance implications involved with doing so, which is why many linters recommend disallowing eval(). However, there are some other ways to pass a string and have it interpreted as JavaScript code that have similar concerns. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// setTimeout('alert("Hi!");', 100); + /// + /// setInterval('alert("Hi!");', 100); + /// + /// setImmediate('alert("Hi!")'); + /// + /// window.setTimeout('count = 5', 10); + /// + /// window.setInterval('foo = bar', 10); + /// + /// const fn = new Function('a', 'b', 'return a + b'); + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// setTimeout(() => { + /// alert('Hi!'); + /// }, 100); + /// + /// setInterval(() => { + /// alert('Hi!'); + /// }, 100); + /// + /// setImmediate(() => { + /// alert('Hi!'); + /// }); + /// + /// const fn = (a: number, b: number) => a + b; + /// ``` + NoImpliedEval(tsgolint), + typescript, + correctness, + pending, +); + +impl Rule for NoImpliedEval {} diff --git a/crates/oxc_linter/src/rules/typescript/no_meaningless_void_operator.rs b/crates/oxc_linter/src/rules/typescript/no_meaningless_void_operator.rs new file mode 100644 index 0000000000000..10d58df2739a2 --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/no_meaningless_void_operator.rs @@ -0,0 +1,56 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct NoMeaninglessVoidOperator; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule disallows the void operator when its argument is already of type void or undefined. + /// + /// ### Why is this bad? + /// + /// The void operator is useful when you want to execute an expression and force it to evaluate to undefined. However, using void on expressions that are already of type void or undefined is meaningless and adds unnecessary complexity to the code. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// function foo(): void { + /// return; + /// } + /// + /// void foo(); // meaningless, foo() already returns void + /// + /// void undefined; // meaningless, undefined is already undefined + /// + /// async function bar() { + /// void (await somePromise); // meaningless if somePromise resolves to void + /// } + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// function getValue(): number { + /// return 42; + /// } + /// + /// void getValue(); // meaningful, converts number to void + /// + /// void console.log('hello'); // meaningful, console.log returns undefined but we want to be explicit + /// + /// function processData() { + /// // some processing + /// } + /// + /// processData(); // no void needed since we don't care about return value + /// ``` + NoMeaninglessVoidOperator(tsgolint), + typescript, + correctness, + pending, +); + +impl Rule for NoMeaninglessVoidOperator {} diff --git a/crates/oxc_linter/src/rules/typescript/no_misused_promises.rs b/crates/oxc_linter/src/rules/typescript/no_misused_promises.rs index 6b118b68f6942..3436a727e7c93 100644 --- a/crates/oxc_linter/src/rules/typescript/no_misused_promises.rs +++ b/crates/oxc_linter/src/rules/typescript/no_misused_promises.rs @@ -53,7 +53,7 @@ declare_oxc_lint!( /// ``` NoMisusedPromises(tsgolint), typescript, - suspicious, + pedantic, pending, ); diff --git a/crates/oxc_linter/src/rules/typescript/no_misused_spread.rs b/crates/oxc_linter/src/rules/typescript/no_misused_spread.rs new file mode 100644 index 0000000000000..e642f6639510e --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/no_misused_spread.rs @@ -0,0 +1,58 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct NoMisusedSpread; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule disallows spreading syntax in places where it doesn't make sense or could cause runtime errors. + /// + /// ### Why is this bad? + /// + /// The spread operator can be misused in ways that might not be immediately obvious but can cause runtime errors or unexpected behavior. This rule helps catch common misuses. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// // Spreading a non-iterable value in an array + /// const num = 42; + /// const arr = [...num]; // Runtime error: num is not iterable + /// + /// // Spreading a Promise in an array + /// const promise = Promise.resolve([1, 2, 3]); + /// const arr2 = [...promise]; // Runtime error: Promise is not iterable + /// + /// // Spreading non-object in object literal + /// const str = 'hello'; + /// const obj = { ...str }; // Creates { '0': 'h', '1': 'e', ... } which might be unexpected + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// // Spreading arrays + /// const arr1 = [1, 2, 3]; + /// const arr2 = [...arr1]; + /// + /// // Spreading objects + /// const obj1 = { a: 1, b: 2 }; + /// const obj2 = { ...obj1 }; + /// + /// // Spreading resolved Promise + /// const promise = Promise.resolve([1, 2, 3]); + /// const arr3 = [...(await promise)]; + /// + /// // Using Array.from for non-iterables if needed + /// const str = 'hello'; + /// const arr4 = Array.from(str); // ['h', 'e', 'l', 'l', 'o'] + /// ``` + NoMisusedSpread(tsgolint), + typescript, + correctness, + pending, +); + +impl Rule for NoMisusedSpread {} diff --git a/crates/oxc_linter/src/rules/typescript/no_mixed_enums.rs b/crates/oxc_linter/src/rules/typescript/no_mixed_enums.rs new file mode 100644 index 0000000000000..f0a34f1e6e665 --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/no_mixed_enums.rs @@ -0,0 +1,63 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct NoMixedEnums; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule disallows enums from having both string and numeric members. + /// + /// ### Why is this bad? + /// + /// TypeScript enums can have string, numeric, or computed members. Having mixed string and numeric members in the same enum can lead to confusion and unexpected runtime behavior due to how TypeScript compiles enums. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// enum Status { + /// Open = 1, + /// Closed = 'closed', + /// } + /// + /// enum Direction { + /// Up = 'up', + /// Down = 2, + /// Left = 'left', + /// Right = 4, + /// } + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// // All numeric + /// enum Status { + /// Open = 1, + /// Closed = 2, + /// } + /// + /// // All string + /// enum Direction { + /// Up = 'up', + /// Down = 'down', + /// Left = 'left', + /// Right = 'right', + /// } + /// + /// // Auto-incremented numeric + /// enum Color { + /// Red, + /// Green, + /// Blue, + /// } + /// ``` + NoMixedEnums(tsgolint), + typescript, + pedantic, + pending, +); + +impl Rule for NoMixedEnums {} diff --git a/crates/oxc_linter/src/rules/typescript/no_redundant_type_constituents.rs b/crates/oxc_linter/src/rules/typescript/no_redundant_type_constituents.rs new file mode 100644 index 0000000000000..c9bfbe535ed0b --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/no_redundant_type_constituents.rs @@ -0,0 +1,57 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct NoRedundantTypeConstituents; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule disallows type constituents of unions and intersections that are redundant. + /// + /// ### Why is this bad? + /// + /// Some constituents of union and intersection types can be redundant due to TypeScript's type system rules. These redundant constituents don't add any value and can make types harder to read and understand. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// // unknown is redundant in unions + /// type T1 = string | unknown; + /// + /// // any is redundant in unions + /// type T2 = string | any; + /// + /// // never is redundant in unions + /// type T3 = string | never; + /// + /// // Literal types that are wider than other types + /// type T4 = string | 'hello'; + /// + /// // Object types that are subsets + /// type T5 = { a: string } | { a: string; b: number }; + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// type T1 = string | number; + /// + /// type T2 = 'hello' | 'world'; + /// + /// type T3 = { a: string } | { b: number }; + /// + /// // unknown in intersections is meaningful + /// type T4 = string & unknown; + /// + /// // never in intersections is meaningful + /// type T5 = string & never; + /// ``` + NoRedundantTypeConstituents(tsgolint), + typescript, + correctness, + pending, +); + +impl Rule for NoRedundantTypeConstituents {} diff --git a/crates/oxc_linter/src/rules/typescript/no_unnecessary_boolean_literal_compare.rs b/crates/oxc_linter/src/rules/typescript/no_unnecessary_boolean_literal_compare.rs new file mode 100644 index 0000000000000..8313f12344750 --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/no_unnecessary_boolean_literal_compare.rs @@ -0,0 +1,66 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct NoUnnecessaryBooleanLiteralCompare; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule disallows unnecessary equality comparisons with boolean literals. + /// + /// ### Why is this bad? + /// + /// Comparing boolean values to boolean literals is unnecessary when the comparison can be eliminated. These comparisons make code more verbose without adding value. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// declare const someCondition: boolean; + /// + /// if (someCondition === true) { + /// // ... + /// } + /// + /// if (someCondition === false) { + /// // ... + /// } + /// + /// if (someCondition !== true) { + /// // ... + /// } + /// + /// if (someCondition !== false) { + /// // ... + /// } + /// + /// const result = someCondition == true; + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// declare const someCondition: boolean; + /// + /// if (someCondition) { + /// // ... + /// } + /// + /// if (!someCondition) { + /// // ... + /// } + /// + /// // Comparisons with non-boolean types are allowed + /// declare const someValue: unknown; + /// if (someValue === true) { + /// // ... + /// } + /// ``` + NoUnnecessaryBooleanLiteralCompare(tsgolint), + typescript, + suspicious, + pending, +); + +impl Rule for NoUnnecessaryBooleanLiteralCompare {} diff --git a/crates/oxc_linter/src/rules/typescript/no_unnecessary_template_expression.rs b/crates/oxc_linter/src/rules/typescript/no_unnecessary_template_expression.rs new file mode 100644 index 0000000000000..2c3785cb9da5f --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/no_unnecessary_template_expression.rs @@ -0,0 +1,58 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct NoUnnecessaryTemplateExpression; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule disallows unnecessary template literals. + /// + /// ### Why is this bad? + /// + /// Template literals should only be used when they are needed for string interpolation or multi-line strings. Using template literals when a simple string would suffice adds unnecessary complexity. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// const str1 = `Hello world`; + /// + /// const str2 = `42`; + /// + /// const str3 = `true`; + /// + /// // Template with only literal expressions + /// const str4 = `${'Hello'} ${'world'}`; + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// const str1 = 'Hello world'; + /// + /// const str2 = '42'; + /// + /// const str3 = 'true'; + /// + /// // Template with variable interpolation + /// const name = 'world'; + /// const str4 = `Hello ${name}`; + /// + /// // Multi-line string + /// const multiline = ` + /// Hello + /// world + /// `; + /// + /// // Template with expression + /// const str5 = `Result: ${1 + 2}`; + /// ``` + NoUnnecessaryTemplateExpression(tsgolint), + typescript, + suspicious, + pending, +); + +impl Rule for NoUnnecessaryTemplateExpression {} diff --git a/crates/oxc_linter/src/rules/typescript/no_unnecessary_type_arguments.rs b/crates/oxc_linter/src/rules/typescript/no_unnecessary_type_arguments.rs new file mode 100644 index 0000000000000..6ce8567012c95 --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/no_unnecessary_type_arguments.rs @@ -0,0 +1,71 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct NoUnnecessaryTypeArguments; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule disallows type arguments that are identical to the default type parameter. + /// + /// ### Why is this bad? + /// + /// Explicit type arguments that are the same as their default values are unnecessary and add visual noise to the code. TypeScript will infer these types automatically. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// function identity(arg: T): T { + /// return arg; + /// } + /// + /// // Unnecessary type argument - string is the default + /// const result = identity('hello'); + /// + /// interface Container { + /// value: T; + /// } + /// + /// // Unnecessary type argument - number is the default + /// const container: Container = { value: 42 }; + /// + /// class MyClass { + /// constructor(public value: T) {} + /// } + /// + /// // Unnecessary type argument - boolean is the default + /// const instance = new MyClass(true); + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// function identity(arg: T): T { + /// return arg; + /// } + /// + /// // Using default type + /// const result1 = identity('hello'); + /// + /// // Using different type + /// const result2 = identity(42); + /// + /// interface Container { + /// value: T; + /// } + /// + /// // Using default type + /// const container1: Container = { value: 42 }; + /// + /// // Using different type + /// const container2: Container = { value: 'hello' }; + /// ``` + NoUnnecessaryTypeArguments(tsgolint), + typescript, + suspicious, + pending, +); + +impl Rule for NoUnnecessaryTypeArguments {} diff --git a/crates/oxc_linter/src/rules/typescript/no_unnecessary_type_assertion.rs b/crates/oxc_linter/src/rules/typescript/no_unnecessary_type_assertion.rs new file mode 100644 index 0000000000000..606030a77a45b --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/no_unnecessary_type_assertion.rs @@ -0,0 +1,56 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct NoUnnecessaryTypeAssertion; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule disallows type assertions that do not change the type of an expression. + /// + /// ### Why is this bad? + /// + /// Type assertions that don't actually change the type of an expression are unnecessary and can be safely removed. They add visual noise without providing any benefit and may indicate confusion about TypeScript's type system. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// const str: string = 'hello'; + /// const redundant = str as string; // unnecessary, str is already string + /// + /// function getString(): string { + /// return 'hello'; + /// } + /// const result = getString() as string; // unnecessary, getString() already returns string + /// + /// const num = 42; + /// const alsoRedundant = num as 42; // unnecessary if TypeScript can infer literal type + /// + /// // Unnecessary assertion to wider type + /// const literal = 'hello' as string; + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// const unknown: unknown = 'hello'; + /// const str = unknown as string; // necessary to narrow type + /// + /// const element = document.getElementById('myElement') as HTMLInputElement; // necessary for specific element type + /// + /// const obj = { name: 'John' }; + /// const name = obj.name as const; // necessary for literal type + /// + /// // No assertion needed + /// const str2: string = 'hello'; + /// const num: number = 42; + /// ``` + NoUnnecessaryTypeAssertion(tsgolint), + typescript, + suspicious, + pending, +); + +impl Rule for NoUnnecessaryTypeAssertion {} diff --git a/crates/oxc_linter/src/rules/typescript/no_unsafe_argument.rs b/crates/oxc_linter/src/rules/typescript/no_unsafe_argument.rs new file mode 100644 index 0000000000000..69d2c7f78ced6 --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/no_unsafe_argument.rs @@ -0,0 +1,59 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct NoUnsafeArgument; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule disallows calling a function with an argument which is typed as `any`. + /// + /// ### Why is this bad? + /// + /// The `any` type in TypeScript is a dangerous "escape hatch" from the type system. Using `any` disables most type checking rules and is generally unsafe. When you pass a value typed as `any` to a function, you lose type safety for that function call. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// declare const anyValue: any; + /// + /// function takesString(str: string): void { + /// console.log(str.length); + /// } + /// + /// takesString(anyValue); // unsafe + /// + /// declare function takesNumber(num: number): number; + /// const result = takesNumber(anyValue); // unsafe + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// declare const stringValue: string; + /// declare const numberValue: number; + /// declare const unknownValue: unknown; + /// + /// function takesString(str: string): void { + /// console.log(str.length); + /// } + /// + /// takesString(stringValue); // safe + /// + /// // Type guard to safely use unknown + /// if (typeof unknownValue === 'string') { + /// takesString(unknownValue); // safe after type guard + /// } + /// + /// // Type assertion if you're sure about the type + /// takesString(unknownValue as string); // explicitly unsafe, but intentional + /// ``` + NoUnsafeArgument(tsgolint), + typescript, + pedantic, + pending, +); + +impl Rule for NoUnsafeArgument {} diff --git a/crates/oxc_linter/src/rules/typescript/no_unsafe_assignment.rs b/crates/oxc_linter/src/rules/typescript/no_unsafe_assignment.rs new file mode 100644 index 0000000000000..1277c464f1d4e --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/no_unsafe_assignment.rs @@ -0,0 +1,65 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct NoUnsafeAssignment; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule disallows assigning a value with type `any` to variables and properties. + /// + /// ### Why is this bad? + /// + /// The `any` type in TypeScript disables type checking and can lead to runtime errors. When you assign an `any` value to a typed variable, you're essentially bypassing TypeScript's type safety without any guarantees about the actual value. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// declare const anyValue: any; + /// + /// const str: string = anyValue; // unsafe assignment + /// + /// let num: number; + /// num = anyValue; // unsafe assignment + /// + /// const obj = { + /// prop: anyValue as any, // unsafe assignment + /// }; + /// + /// interface User { + /// name: string; + /// age: number; + /// } + /// + /// const user: User = anyValue; // unsafe assignment + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// declare const stringValue: string; + /// declare const numberValue: number; + /// declare const unknownValue: unknown; + /// + /// const str: string = stringValue; // safe + /// + /// let num: number; + /// num = numberValue; // safe + /// + /// // Use type guards with unknown + /// if (typeof unknownValue === 'string') { + /// const str2: string = unknownValue; // safe after type guard + /// } + /// + /// // Explicit any assignment (still not recommended, but intentional) + /// const anything: any = unknownValue; + /// ``` + NoUnsafeAssignment(tsgolint), + typescript, + pedantic, + pending, +); + +impl Rule for NoUnsafeAssignment {} diff --git a/crates/oxc_linter/src/rules/typescript/no_unsafe_call.rs b/crates/oxc_linter/src/rules/typescript/no_unsafe_call.rs new file mode 100644 index 0000000000000..be14df049969a --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/no_unsafe_call.rs @@ -0,0 +1,57 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct NoUnsafeCall; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule disallows calling a value with type `any`. + /// + /// ### Why is this bad? + /// + /// The `any` type in TypeScript disables type checking. When you call a value typed as `any`, TypeScript cannot verify that it's actually a function, what parameters it expects, or what it returns. This can lead to runtime errors. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// declare const anyValue: any; + /// + /// anyValue(); // unsafe call + /// + /// anyValue(1, 2, 3); // unsafe call + /// + /// const result = anyValue('hello'); // unsafe call + /// + /// // Chained unsafe calls + /// anyValue().then().catch(); // unsafe + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// declare const fn: () => void; + /// declare const fnWithParams: (a: number, b: string) => boolean; + /// declare const unknownValue: unknown; + /// + /// fn(); // safe + /// + /// const result = fnWithParams(1, 'hello'); // safe + /// + /// // Type guard for unknown + /// if (typeof unknownValue === 'function') { + /// unknownValue(); // safe after type guard + /// } + /// + /// // Explicit type assertion if you're certain + /// (anyValue as () => void)(); // explicitly unsafe but intentional + /// ``` + NoUnsafeCall(tsgolint), + typescript, + pedantic, + pending, +); + +impl Rule for NoUnsafeCall {} diff --git a/crates/oxc_linter/src/rules/typescript/no_unsafe_enum_comparison.rs b/crates/oxc_linter/src/rules/typescript/no_unsafe_enum_comparison.rs new file mode 100644 index 0000000000000..4cd09a9d162f5 --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/no_unsafe_enum_comparison.rs @@ -0,0 +1,69 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct NoUnsafeEnumComparison; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule disallows comparing an enum value with a non-enum value. + /// + /// ### Why is this bad? + /// + /// Enum values should only be compared with other values of the same enum type or their underlying literal values in a type-safe manner. Comparing enums with unrelated values can lead to unexpected behavior and defeats the purpose of using enums for type safety. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// enum Status { + /// Open = 'open', + /// Closed = 'closed', + /// } + /// + /// enum Color { + /// Red = 'red', + /// Blue = 'blue', + /// } + /// + /// declare const status: Status; + /// declare const color: Color; + /// declare const str: string; + /// + /// // Comparing enum with different enum + /// if (status === color) {} // unsafe + /// + /// // Comparing enum with string (unless it's a literal that matches) + /// if (status === str) {} // unsafe + /// + /// // Comparing with arbitrary value + /// if (status === 'unknown') {} // unsafe + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// enum Status { + /// Open = 'open', + /// Closed = 'closed', + /// } + /// + /// declare const status: Status; + /// + /// // Comparing with same enum values + /// if (status === Status.Open) {} // safe + /// + /// // Comparing with the correct literal type + /// if (status === 'open') {} // safe + /// + /// // Using enum methods + /// if (Object.values(Status).includes(someValue)) {} // safe way to check + /// ``` + NoUnsafeEnumComparison(tsgolint), + typescript, + suspicious, + pending, +); + +impl Rule for NoUnsafeEnumComparison {} diff --git a/crates/oxc_linter/src/rules/typescript/no_unsafe_member_access.rs b/crates/oxc_linter/src/rules/typescript/no_unsafe_member_access.rs new file mode 100644 index 0000000000000..dd2b3d7a3f7a6 --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/no_unsafe_member_access.rs @@ -0,0 +1,57 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct NoUnsafeMemberAccess; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule disallows member access on a value with type `any`. + /// + /// ### Why is this bad? + /// + /// The `any` type in TypeScript disables type checking. When you access a member (property or method) on a value typed as `any`, TypeScript cannot verify that the member exists or what type it has. This can lead to runtime errors. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// declare const anyValue: any; + /// + /// anyValue.foo; // unsafe member access + /// + /// anyValue.bar.baz; // unsafe nested member access + /// + /// anyValue['key']; // unsafe computed member access + /// + /// const result = anyValue.method(); // unsafe method access + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// declare const obj: { foo: string; bar: { baz: number } }; + /// declare const unknownValue: unknown; + /// + /// obj.foo; // safe + /// + /// obj.bar.baz; // safe + /// + /// obj['foo']; // safe + /// + /// // Type guard for unknown + /// if (typeof unknownValue === 'object' && unknownValue !== null && 'foo' in unknownValue) { + /// console.log(unknownValue.foo); // safe after type guard + /// } + /// + /// // Explicit type assertion if needed + /// (anyValue as { foo: string }).foo; // explicitly unsafe but intentional + /// ``` + NoUnsafeMemberAccess(tsgolint), + typescript, + pedantic, + pending, +); + +impl Rule for NoUnsafeMemberAccess {} diff --git a/crates/oxc_linter/src/rules/typescript/no_unsafe_return.rs b/crates/oxc_linter/src/rules/typescript/no_unsafe_return.rs new file mode 100644 index 0000000000000..f4f2717dd0ed9 --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/no_unsafe_return.rs @@ -0,0 +1,64 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct NoUnsafeReturn; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule disallows returning a value with type `any` from a function. + /// + /// ### Why is this bad? + /// + /// The `any` type in TypeScript disables type checking. When you return a value typed as `any` from a function, you're essentially passing the type-safety problem to the caller without providing any guarantees about what the function actually returns. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// declare const anyValue: any; + /// + /// function getString(): string { + /// return anyValue; // unsafe return + /// } + /// + /// const getNumber = (): number => anyValue; // unsafe return + /// + /// function processData(): { name: string; age: number } { + /// return anyValue; // unsafe return + /// } + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// declare const stringValue: string; + /// declare const numberValue: number; + /// declare const unknownValue: unknown; + /// + /// function getString(): string { + /// return stringValue; // safe + /// } + /// + /// const getNumber = (): number => numberValue; // safe + /// + /// function processUnknown(): unknown { + /// return unknownValue; // safe - explicitly returning unknown + /// } + /// + /// // Type guard to safely return + /// function safeGetString(): string | null { + /// if (typeof unknownValue === 'string') { + /// return unknownValue; // safe after type guard + /// } + /// return null; + /// } + /// ``` + NoUnsafeReturn(tsgolint), + typescript, + pedantic, + pending, +); + +impl Rule for NoUnsafeReturn {} diff --git a/crates/oxc_linter/src/rules/typescript/no_unsafe_type_assertion.rs b/crates/oxc_linter/src/rules/typescript/no_unsafe_type_assertion.rs new file mode 100644 index 0000000000000..7879a1fa714ee --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/no_unsafe_type_assertion.rs @@ -0,0 +1,62 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct NoUnsafeTypeAssertion; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule disallows type assertions using the `any` type. + /// + /// ### Why is this bad? + /// + /// Type assertions using `any` completely bypass TypeScript's type system and can lead to runtime errors. They should be avoided in favor of more specific type assertions or proper type guards. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// declare const value: unknown; + /// + /// const str = value as any; // unsafe type assertion + /// + /// const obj = value as any as string; // double assertion through any + /// + /// function processValue(input: unknown) { + /// const processed = input as any; // unsafe + /// return processed.someProperty; + /// } + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// declare const value: unknown; + /// + /// // Use specific type assertions + /// const str = value as string; // more specific assertion + /// + /// // Use type guards + /// if (typeof value === 'string') { + /// const str2 = value; // safe, no assertion needed + /// } + /// + /// // Use proper interface assertions + /// interface User { + /// name: string; + /// age: number; + /// } + /// + /// const user = value as User; // specific type assertion + /// + /// // Use unknown for truly unknown values + /// const unknown: unknown = value; + /// ``` + NoUnsafeTypeAssertion(tsgolint), + typescript, + suspicious, + pending, +); + +impl Rule for NoUnsafeTypeAssertion {} diff --git a/crates/oxc_linter/src/rules/typescript/no_unsafe_unary_minus.rs b/crates/oxc_linter/src/rules/typescript/no_unsafe_unary_minus.rs new file mode 100644 index 0000000000000..98e217138a18d --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/no_unsafe_unary_minus.rs @@ -0,0 +1,62 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct NoUnsafeUnaryMinus; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule disallows using the unary minus operator on a value which is not of type 'number' | 'bigint'. + /// + /// ### Why is this bad? + /// + /// The unary minus operator should only be used on numeric values. Using it on other types can lead to unexpected behavior due to JavaScript's type coercion rules. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// declare const value: any; + /// const result1 = -value; // unsafe on any + /// + /// declare const str: string; + /// const result2 = -str; // unsafe on string + /// + /// declare const bool: boolean; + /// const result3 = -bool; // unsafe on boolean + /// + /// declare const obj: object; + /// const result4 = -obj; // unsafe on object + /// + /// declare const arr: any[]; + /// const result5 = -arr; // unsafe on array + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// declare const num: number; + /// const result1 = -num; // safe + /// + /// declare const bigint: bigint; + /// const result2 = -bigint; // safe + /// + /// const literal = -42; // safe + /// + /// const bigintLiteral = -42n; // safe + /// + /// declare const union: number | bigint; + /// const result3 = -union; // safe + /// + /// // Convert to number first if needed + /// declare const str: string; + /// const result4 = -Number(str); // safe conversion + /// ``` + NoUnsafeUnaryMinus(tsgolint), + typescript, + correctness, + pending, +); + +impl Rule for NoUnsafeUnaryMinus {} diff --git a/crates/oxc_linter/src/rules/typescript/non_nullable_type_assertion_style.rs b/crates/oxc_linter/src/rules/typescript/non_nullable_type_assertion_style.rs new file mode 100644 index 0000000000000..719a8ce0e04e0 --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/non_nullable_type_assertion_style.rs @@ -0,0 +1,64 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct NonNullableTypeAssertionStyle; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule prefers a non-null assertion over an explicit type cast for non-nullable types. + /// + /// ### Why is this bad? + /// + /// When you know that a value cannot be null or undefined, you can use either a non-null assertion (`!`) or a type assertion (`as Type`). The non-null assertion is more concise and clearly communicates the intent that you're asserting the value is not null/undefined. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// declare const value: string | null; + /// + /// // Type assertion when non-null assertion would be clearer + /// const result1 = value as string; + /// + /// declare const maybe: number | undefined; + /// const result2 = maybe as number; + /// + /// // In function calls + /// function takesString(s: string) { + /// console.log(s); + /// } + /// + /// takesString(value as string); + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// declare const value: string | null; + /// + /// // Non-null assertion for non-nullable types + /// const result1 = value!; + /// + /// declare const maybe: number | undefined; + /// const result2 = maybe!; + /// + /// // In function calls + /// function takesString(s: string) { + /// console.log(s); + /// } + /// + /// takesString(value!); + /// + /// // Type assertion for actual type changes is still fine + /// declare const unknown: unknown; + /// const str = unknown as string; // This is a different type, not just removing null + /// ``` + NonNullableTypeAssertionStyle(tsgolint), + typescript, + restriction, + pending, +); + +impl Rule for NonNullableTypeAssertionStyle {} diff --git a/crates/oxc_linter/src/rules/typescript/only_throw_error.rs b/crates/oxc_linter/src/rules/typescript/only_throw_error.rs new file mode 100644 index 0000000000000..a3a9c5e13507e --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/only_throw_error.rs @@ -0,0 +1,64 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct OnlyThrowError; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule disallows throwing non-Error values. + /// + /// ### Why is this bad? + /// + /// It's considered good practice to only throw Error objects (or subclasses of Error). This is because Error objects automatically capture a stack trace, which is useful for debugging. Additionally, some tools and environments expect thrown values to be Error objects. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// throw 'error'; // throwing string + /// + /// throw 42; // throwing number + /// + /// throw true; // throwing boolean + /// + /// throw { message: 'error' }; // throwing plain object + /// + /// throw null; // throwing null + /// + /// throw undefined; // throwing undefined + /// + /// const error = 'Something went wrong'; + /// throw error; // throwing non-Error variable + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// throw new Error('Something went wrong'); + /// + /// throw new TypeError('Invalid type'); + /// + /// throw new RangeError('Value out of range'); + /// + /// // Custom Error subclasses + /// class CustomError extends Error { + /// constructor(message: string) { + /// super(message); + /// this.name = 'CustomError'; + /// } + /// } + /// throw new CustomError('Custom error occurred'); + /// + /// // Variables that are Error objects + /// const error = new Error('Error message'); + /// throw error; + /// ``` + OnlyThrowError(tsgolint), + typescript, + pedantic, + pending, +); + +impl Rule for OnlyThrowError {} diff --git a/crates/oxc_linter/src/rules/typescript/prefer_promise_reject_errors.rs b/crates/oxc_linter/src/rules/typescript/prefer_promise_reject_errors.rs new file mode 100644 index 0000000000000..a1e647e98e997 --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/prefer_promise_reject_errors.rs @@ -0,0 +1,64 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct PreferPromiseRejectErrors; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule enforces passing an Error object to Promise.reject(). + /// + /// ### Why is this bad? + /// + /// It's considered good practice to only reject promises with Error objects. This is because Error objects automatically capture a stack trace, which is useful for debugging. Additionally, some tools and environments expect rejection reasons to be Error objects. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// Promise.reject('error'); // rejecting with string + /// + /// Promise.reject(42); // rejecting with number + /// + /// Promise.reject(true); // rejecting with boolean + /// + /// Promise.reject({ message: 'error' }); // rejecting with plain object + /// + /// Promise.reject(null); // rejecting with null + /// + /// Promise.reject(); // rejecting with undefined + /// + /// const error = 'Something went wrong'; + /// Promise.reject(error); // rejecting with non-Error variable + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// Promise.reject(new Error('Something went wrong')); + /// + /// Promise.reject(new TypeError('Invalid type')); + /// + /// Promise.reject(new RangeError('Value out of range')); + /// + /// // Custom Error subclasses + /// class CustomError extends Error { + /// constructor(message: string) { + /// super(message); + /// this.name = 'CustomError'; + /// } + /// } + /// Promise.reject(new CustomError('Custom error occurred')); + /// + /// // Variables that are Error objects + /// const error = new Error('Error message'); + /// Promise.reject(error); + /// ``` + PreferPromiseRejectErrors(tsgolint), + typescript, + pedantic, + pending, +); + +impl Rule for PreferPromiseRejectErrors {} diff --git a/crates/oxc_linter/src/rules/typescript/prefer_reduce_type_parameter.rs b/crates/oxc_linter/src/rules/typescript/prefer_reduce_type_parameter.rs new file mode 100644 index 0000000000000..b0a4b7b126014 --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/prefer_reduce_type_parameter.rs @@ -0,0 +1,65 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct PreferReduceTypeParameter; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule prefers using a type parameter for the accumulator in Array.reduce instead of casting. + /// + /// ### Why is this bad? + /// + /// Array.reduce can be called with a generic type parameter to specify the type of the accumulator. This is preferred over casting the result because it provides better type safety and is more explicit about the intended type. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// const numbers = [1, 2, 3]; + /// + /// // Casting the result + /// const sum = numbers.reduce((acc, val) => acc + val, 0) as number; + /// + /// // Using type assertion on accumulator + /// const result = [1, 2, 3].reduce((acc: string[], curr) => { + /// acc.push(curr.toString()); + /// return acc; + /// }, [] as string[]); + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// const numbers = [1, 2, 3]; + /// + /// // Using type parameter + /// const sum = numbers.reduce((acc, val) => acc + val, 0); + /// + /// // Type parameter for complex types + /// const result = [1, 2, 3].reduce((acc, curr) => { + /// acc.push(curr.toString()); + /// return acc; + /// }, []); + /// + /// // When TypeScript can infer the type, no parameter needed + /// const simpleSum = numbers.reduce((acc, val) => acc + val, 0); + /// + /// // Object accumulator with type parameter + /// interface Count { + /// [key: string]: number; + /// } + /// + /// const counts = ['a', 'b', 'a'].reduce((acc, item) => { + /// acc[item] = (acc[item] || 0) + 1; + /// return acc; + /// }, {}); + /// ``` + PreferReduceTypeParameter(tsgolint), + typescript, + style, + pending, +); + +impl Rule for PreferReduceTypeParameter {} diff --git a/crates/oxc_linter/src/rules/typescript/prefer_return_this_type.rs b/crates/oxc_linter/src/rules/typescript/prefer_return_this_type.rs new file mode 100644 index 0000000000000..c4e496a81cf26 --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/prefer_return_this_type.rs @@ -0,0 +1,84 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct PreferReturnThisType; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule enforces using `this` types for return types when possible. + /// + /// ### Why is this bad? + /// + /// Classes that have methods which return the instance itself should use `this` as the return type instead of the class name. This provides better type safety for inheritance, as the return type will be the actual subclass type rather than the base class type. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// class Builder { + /// private value: string = ''; + /// + /// setValue(value: string): Builder { // Should return 'this' + /// this.value = value; + /// return this; + /// } + /// + /// build(): string { + /// return this.value; + /// } + /// } + /// + /// class FluentAPI { + /// method1(): FluentAPI { // Should return 'this' + /// return this; + /// } + /// + /// method2(): FluentAPI { // Should return 'this' + /// return this; + /// } + /// } + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// class Builder { + /// private value: string = ''; + /// + /// setValue(value: string): this { + /// this.value = value; + /// return this; + /// } + /// + /// build(): string { + /// return this.value; + /// } + /// } + /// + /// class FluentAPI { + /// method1(): this { + /// return this; + /// } + /// + /// method2(): this { + /// return this; + /// } + /// } + /// + /// // Now inheritance works correctly + /// class ExtendedBuilder extends Builder { + /// setPrefix(prefix: string): this { + /// // The return type is 'this' (ExtendedBuilder), not Builder + /// return this.setValue(prefix + this.getValue()); + /// } + /// } + /// ``` + PreferReturnThisType(tsgolint), + typescript, + style, + pending, +); + +impl Rule for PreferReturnThisType {} diff --git a/crates/oxc_linter/src/rules/typescript/promise_function_async.rs b/crates/oxc_linter/src/rules/typescript/promise_function_async.rs new file mode 100644 index 0000000000000..51b57ed113b40 --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/promise_function_async.rs @@ -0,0 +1,76 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct PromiseFunctionAsync; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule requires any function or method that returns a Promise to be marked as async. + /// + /// ### Why is this bad? + /// + /// Functions that return Promises should typically be marked as `async` to make their asynchronous nature clear and to enable the use of `await` within them. This makes the code more readable and helps prevent common mistakes with Promise handling. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// // Function returning Promise without async + /// function fetchData(): Promise { + /// return fetch('/api/data').then(res => res.text()); + /// } + /// + /// // Method returning Promise without async + /// class DataService { + /// getData(): Promise { + /// return fetch('/api/data').then(res => res.json()); + /// } + /// } + /// + /// // Arrow function returning Promise without async + /// const processData = (): Promise => { + /// return Promise.resolve(); + /// }; + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// // Async function + /// async function fetchData(): Promise { + /// const response = await fetch('/api/data'); + /// return response.text(); + /// } + /// + /// // Async method + /// class DataService { + /// async getData(): Promise { + /// const response = await fetch('/api/data'); + /// return response.json(); + /// } + /// } + /// + /// // Async arrow function + /// const processData = async (): Promise => { + /// await someAsyncOperation(); + /// }; + /// + /// // Functions that don't return Promise are fine + /// function syncFunction(): string { + /// return 'hello'; + /// } + /// + /// // Functions returning Promise-like but not actual Promise + /// function createThenable(): { then: Function } { + /// return { then: () => {} }; + /// } + /// ``` + PromiseFunctionAsync(tsgolint), + typescript, + restriction, + pending, +); + +impl Rule for PromiseFunctionAsync {} diff --git a/crates/oxc_linter/src/rules/typescript/related_getter_setter_pairs.rs b/crates/oxc_linter/src/rules/typescript/related_getter_setter_pairs.rs new file mode 100644 index 0000000000000..72d3f72438052 --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/related_getter_setter_pairs.rs @@ -0,0 +1,78 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct RelatedGetterSetterPairs; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule enforces that getters and setters for the same property are defined together and have related types. + /// + /// ### Why is this bad? + /// + /// When you define a getter and setter for the same property, they should typically be defined together and work with compatible types. Having mismatched types or defining them separately can lead to confusion and potential runtime errors. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// class Example { + /// // Getter and setter with incompatible types + /// get value(): string { + /// return this._value.toString(); + /// } + /// + /// set value(val: number) { // Incompatible with getter + /// this._value = val; + /// } + /// + /// private _value: number = 0; + /// } + /// + /// // Getter without corresponding setter or vice versa might be flagged + /// class IncompleteProperty { + /// get readOnlyValue(): string { + /// return 'constant'; + /// } + /// // Missing setter - might be intended, but should be consistent + /// } + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// class Example { + /// // Getter and setter with compatible types + /// get value(): string { + /// return this._value; + /// } + /// + /// set value(val: string) { + /// this._value = val; + /// } + /// + /// private _value: string = ''; + /// } + /// + /// // Read-only property with only getter + /// class ReadOnlyProperty { + /// get constant(): string { + /// return 'constant value'; + /// } + /// } + /// + /// // Write-only property with only setter (less common but valid) + /// class WriteOnlyProperty { + /// set logger(message: string) { + /// console.log(message); + /// } + /// } + /// ``` + RelatedGetterSetterPairs(tsgolint), + typescript, + pedantic, + pending, +); + +impl Rule for RelatedGetterSetterPairs {} diff --git a/crates/oxc_linter/src/rules/typescript/require_array_sort_compare.rs b/crates/oxc_linter/src/rules/typescript/require_array_sort_compare.rs new file mode 100644 index 0000000000000..c37b1fdb697ef --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/require_array_sort_compare.rs @@ -0,0 +1,64 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct RequireArraySortCompare; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule requires Array.sort() to be called with a comparison function. + /// + /// ### Why is this bad? + /// + /// When Array.sort() is called without a comparison function, it converts elements to strings and sorts them lexicographically. This often leads to unexpected results, especially with numbers where `[1, 10, 2].sort()` returns `[1, 10, 2]` instead of `[1, 2, 10]`. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// const numbers = [3, 1, 4, 1, 5]; + /// numbers.sort(); // Lexicographic sort, not numeric + /// + /// const mixedArray = ['10', '2', '1']; + /// mixedArray.sort(); // Might be intended, but explicit compareFn is clearer + /// + /// [3, 1, 4].sort(); // Will sort as strings: ['1', '3', '4'] + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// const numbers = [3, 1, 4, 1, 5]; + /// + /// // Numeric sort + /// numbers.sort((a, b) => a - b); + /// + /// // Reverse numeric sort + /// numbers.sort((a, b) => b - a); + /// + /// // String sort (explicit) + /// const strings = ['banana', 'apple', 'cherry']; + /// strings.sort((a, b) => a.localeCompare(b)); + /// + /// // Custom object sorting + /// interface Person { + /// name: string; + /// age: number; + /// } + /// + /// const people: Person[] = [ + /// { name: 'Alice', age: 30 }, + /// { name: 'Bob', age: 25 }, + /// ]; + /// + /// people.sort((a, b) => a.age - b.age); + /// people.sort((a, b) => a.name.localeCompare(b.name)); + /// ``` + RequireArraySortCompare(tsgolint), + typescript, + correctness, + pending, +); + +impl Rule for RequireArraySortCompare {} diff --git a/crates/oxc_linter/src/rules/typescript/require_await.rs b/crates/oxc_linter/src/rules/typescript/require_await.rs new file mode 100644 index 0000000000000..60eb475169e1d --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/require_await.rs @@ -0,0 +1,80 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct RequireAwait; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule disallows async functions which do not have an await expression. + /// + /// ### Why is this bad? + /// + /// Async functions that don't use await are usually a mistake. They return a Promise unnecessarily and can often be converted to regular functions. This can improve performance and make the code clearer. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// // Async function without await + /// async function fetchData() { + /// return fetch('/api/data'); + /// } + /// + /// // Async arrow function without await + /// const processData = async () => { + /// return someData.map(x => x * 2); + /// }; + /// + /// // Async method without await + /// class DataService { + /// async getData() { + /// return this.data; + /// } + /// } + /// + /// // Async function that returns Promise but doesn't await + /// async function getPromise() { + /// return Promise.resolve('value'); + /// } + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// // Async function with await + /// async function fetchData() { + /// const response = await fetch('/api/data'); + /// return response.json(); + /// } + /// + /// // Regular function returning Promise + /// function fetchDataSync() { + /// return fetch('/api/data'); + /// } + /// + /// // Async function with await in conditional + /// async function conditionalAwait(condition: boolean) { + /// if (condition) { + /// return await someAsyncOperation(); + /// } + /// return 'default'; + /// } + /// + /// // Async function with await in loop + /// async function processItems(items: string[]) { + /// const results = []; + /// for (const item of items) { + /// results.push(await processItem(item)); + /// } + /// return results; + /// } + /// ``` + RequireAwait(tsgolint), + typescript, + pedantic, + pending, +); + +impl Rule for RequireAwait {} diff --git a/crates/oxc_linter/src/rules/typescript/restrict_plus_operands.rs b/crates/oxc_linter/src/rules/typescript/restrict_plus_operands.rs new file mode 100644 index 0000000000000..48e26f281b763 --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/restrict_plus_operands.rs @@ -0,0 +1,66 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct RestrictPlusOperands; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule requires both operands of addition to be the same type and be number, string, or any. + /// + /// ### Why is this bad? + /// + /// JavaScript's + operator can be used for both numeric addition and string concatenation. When the operands are of different types, JavaScript's type coercion rules can lead to unexpected results. This rule helps prevent these issues by requiring both operands to be of compatible types. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// declare const num: number; + /// declare const str: string; + /// declare const bool: boolean; + /// declare const obj: object; + /// + /// // Mixed types + /// const result1 = num + str; // number + string + /// const result2 = str + bool; // string + boolean + /// const result3 = num + bool; // number + boolean + /// const result4 = obj + str; // object + string + /// + /// // Literals with different types + /// const result5 = 42 + 'hello'; // number literal + string literal + /// const result6 = true + 5; // boolean literal + number literal + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// declare const num1: number; + /// declare const num2: number; + /// declare const str1: string; + /// declare const str2: string; + /// + /// // Same types + /// const sum = num1 + num2; // number + number + /// const concat = str1 + str2; // string + string + /// + /// // Explicit conversions + /// const result1 = num1 + String(num2); // Convert to string first + /// const result2 = String(num1) + str1; // Convert to string first + /// const result3 = Number(str1) + num1; // Convert to number first + /// + /// // Template literals for string concatenation + /// const result4 = `${num1}${str1}`; // Clear intent to concatenate + /// + /// // Literals of same type + /// const numResult = 42 + 58; // number + number + /// const strResult = 'hello' + 'world'; // string + string + /// ``` + RestrictPlusOperands(tsgolint), + typescript, + pedantic, + pending, +); + +impl Rule for RestrictPlusOperands {} diff --git a/crates/oxc_linter/src/rules/typescript/restrict_template_expressions.rs b/crates/oxc_linter/src/rules/typescript/restrict_template_expressions.rs new file mode 100644 index 0000000000000..20171017f11e0 --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/restrict_template_expressions.rs @@ -0,0 +1,74 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct RestrictTemplateExpressions; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule restricts the types allowed in template literal expressions. + /// + /// ### Why is this bad? + /// + /// Template literals will call toString() on the interpolated values. Some types don't have meaningful string representations (like objects that become "[object Object]") or may not have a toString method at all. This rule helps ensure that only appropriate types are used in template expressions. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// declare const obj: object; + /// declare const sym: symbol; + /// declare const fn: () => void; + /// declare const arr: unknown[]; + /// + /// // Objects become "[object Object]" + /// const str1 = `Value: ${obj}`; + /// + /// // Symbols might not be what you expect + /// const str2 = `Symbol: ${sym}`; + /// + /// // Functions become their source code or "[Function]" + /// const str3 = `Function: ${fn}`; + /// + /// // Arrays might not format as expected + /// const str4 = `Array: ${arr}`; + /// + /// // undefined/null become "undefined"/"null" which might be confusing + /// declare const maybeValue: string | undefined; + /// const str5 = `Value: ${maybeValue}`; // Could be "Value: undefined" + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// declare const str: string; + /// declare const num: number; + /// declare const bool: boolean; + /// declare const obj: object; + /// + /// // Safe types + /// const result1 = `String: ${str}`; + /// const result2 = `Number: ${num}`; + /// const result3 = `Boolean: ${bool}`; + /// + /// // Explicit conversions for complex types + /// const result4 = `Object: ${JSON.stringify(obj)}`; + /// const result5 = `Array: ${arr.join(', ')}`; + /// + /// // Handle undefined/null explicitly + /// declare const maybeValue: string | undefined; + /// const result6 = `Value: ${maybeValue ?? 'N/A'}`; + /// const result7 = `Value: ${maybeValue || 'default'}`; + /// + /// // Type guards for unknown values + /// declare const unknown: unknown; + /// const result8 = typeof unknown === 'string' ? `Value: ${unknown}` : 'Invalid'; + /// ``` + RestrictTemplateExpressions(tsgolint), + typescript, + correctness, + pending, +); + +impl Rule for RestrictTemplateExpressions {} diff --git a/crates/oxc_linter/src/rules/typescript/return_await.rs b/crates/oxc_linter/src/rules/typescript/return_await.rs new file mode 100644 index 0000000000000..8c15d8e9395dc --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/return_await.rs @@ -0,0 +1,76 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct ReturnAwait; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule enforces consistent returning of awaited values from async functions. + /// + /// ### Why is this bad? + /// + /// There are different patterns for returning awaited values from async functions. Sometimes you want to await before returning (to handle errors in the current function), and sometimes you want to return the Promise directly (for better performance). This rule helps enforce consistency. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule (depending on configuration): + /// ```ts + /// // If configured to require await: + /// async function fetchData() { + /// return fetch('/api/data'); // Should be: return await fetch('/api/data'); + /// } + /// + /// async function processData() { + /// return someAsyncOperation(); // Should be: return await someAsyncOperation(); + /// } + /// + /// // If configured to disallow unnecessary await: + /// async function fetchData() { + /// return await fetch('/api/data'); // Should be: return fetch('/api/data'); + /// } + /// + /// async function processData() { + /// return await someAsyncOperation(); // Should be: return someAsyncOperation(); + /// } + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// // When await is required for error handling: + /// async function fetchData() { + /// try { + /// return await fetch('/api/data'); + /// } catch (error) { + /// console.error('Fetch failed:', error); + /// throw error; + /// } + /// } + /// + /// // When returning Promise directly for performance: + /// async function fetchData() { + /// return fetch('/api/data'); + /// } + /// + /// // Processing before return requires await: + /// async function fetchAndProcess() { + /// const response = await fetch('/api/data'); + /// return response.json(); + /// } + /// + /// // Multiple async operations: + /// async function multipleOperations() { + /// const data1 = await fetchData1(); + /// const data2 = await fetchData2(); + /// return data1 + data2; + /// } + /// ``` + ReturnAwait(tsgolint), + typescript, + pedantic, + pending, +); + +impl Rule for ReturnAwait {} diff --git a/crates/oxc_linter/src/rules/typescript/switch_exhaustiveness_check.rs b/crates/oxc_linter/src/rules/typescript/switch_exhaustiveness_check.rs new file mode 100644 index 0000000000000..9138495fb7256 --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/switch_exhaustiveness_check.rs @@ -0,0 +1,106 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct SwitchExhaustivenessCheck; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule requires switch statements to be exhaustive when switching on union types. + /// + /// ### Why is this bad? + /// + /// When switching on a union type, it's important to handle all possible cases to avoid runtime errors. TypeScript can help ensure exhaustiveness, but only if the switch statement is properly structured with a default case that TypeScript can analyze. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// type Status = 'pending' | 'approved' | 'rejected'; + /// + /// function handleStatus(status: Status) { + /// switch (status) { + /// case 'pending': + /// return 'Waiting for approval'; + /// case 'approved': + /// return 'Request approved'; + /// // Missing 'rejected' case + /// } + /// } + /// + /// enum Color { + /// Red, + /// Green, + /// Blue, + /// } + /// + /// function getColorName(color: Color) { + /// switch (color) { + /// case Color.Red: + /// return 'red'; + /// case Color.Green: + /// return 'green'; + /// // Missing Color.Blue case + /// } + /// } + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// type Status = 'pending' | 'approved' | 'rejected'; + /// + /// function handleStatus(status: Status) { + /// switch (status) { + /// case 'pending': + /// return 'Waiting for approval'; + /// case 'approved': + /// return 'Request approved'; + /// case 'rejected': + /// return 'Request rejected'; + /// } + /// } + /// + /// // Or with default case for exhaustiveness checking + /// function handleStatusWithDefault(status: Status) { + /// switch (status) { + /// case 'pending': + /// return 'Waiting for approval'; + /// case 'approved': + /// return 'Request approved'; + /// case 'rejected': + /// return 'Request rejected'; + /// default: + /// const _exhaustiveCheck: never = status; + /// return _exhaustiveCheck; + /// } + /// } + /// + /// enum Color { + /// Red, + /// Green, + /// Blue, + /// } + /// + /// function getColorName(color: Color) { + /// switch (color) { + /// case Color.Red: + /// return 'red'; + /// case Color.Green: + /// return 'green'; + /// case Color.Blue: + /// return 'blue'; + /// default: + /// const _exhaustiveCheck: never = color; + /// return _exhaustiveCheck; + /// } + /// } + /// ``` + SwitchExhaustivenessCheck(tsgolint), + typescript, + pedantic, + pending, +); + +impl Rule for SwitchExhaustivenessCheck {} diff --git a/crates/oxc_linter/src/rules/typescript/unbound_method.rs b/crates/oxc_linter/src/rules/typescript/unbound_method.rs new file mode 100644 index 0000000000000..7268927cf2cf0 --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/unbound_method.rs @@ -0,0 +1,92 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct UnboundMethod; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule enforces unbound methods are called with their expected scope. + /// + /// ### Why is this bad? + /// + /// When you extract a method from an object and call it separately, the `this` context is lost. This can lead to runtime errors or unexpected behavior, especially with methods that rely on `this` to access instance properties or other methods. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// class MyClass { + /// private value = 42; + /// + /// getValue() { + /// return this.value; + /// } + /// + /// processValue() { + /// return this.value * 2; + /// } + /// } + /// + /// const instance = new MyClass(); + /// + /// // Unbound method - loses 'this' context + /// const getValue = instance.getValue; + /// getValue(); // Runtime error: cannot read property 'value' of undefined + /// + /// // Passing unbound method as callback + /// [1, 2, 3].map(instance.processValue); // 'this' will be undefined + /// + /// // Destructuring methods + /// const { getValue: unboundGetValue } = instance; + /// unboundGetValue(); // Runtime error + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// class MyClass { + /// private value = 42; + /// + /// getValue() { + /// return this.value; + /// } + /// + /// processValue() { + /// return this.value * 2; + /// } + /// } + /// + /// const instance = new MyClass(); + /// + /// // Call method on instance + /// const value = instance.getValue(); // Correct + /// + /// // Bind method to preserve context + /// const boundGetValue = instance.getValue.bind(instance); + /// boundGetValue(); // Correct + /// + /// // Use arrow function to preserve context + /// [1, 2, 3].map(() => instance.processValue()); // Correct + /// + /// // Use arrow function in class for auto-binding + /// class MyClassWithArrow { + /// private value = 42; + /// + /// getValue = () => { + /// return this.value; + /// }; + /// } + /// + /// const instance2 = new MyClassWithArrow(); + /// const getValue = instance2.getValue; // Safe - arrow function preserves 'this' + /// getValue(); // Correct + /// ``` + UnboundMethod(tsgolint), + typescript, + correctness, + pending, +); + +impl Rule for UnboundMethod {} diff --git a/crates/oxc_linter/src/rules/typescript/use_unknown_in_catch_callback_variable.rs b/crates/oxc_linter/src/rules/typescript/use_unknown_in_catch_callback_variable.rs new file mode 100644 index 0000000000000..c551fb6979f4b --- /dev/null +++ b/crates/oxc_linter/src/rules/typescript/use_unknown_in_catch_callback_variable.rs @@ -0,0 +1,85 @@ +use oxc_macros::declare_oxc_lint; + +use crate::rule::Rule; + +#[derive(Debug, Default, Clone)] +pub struct UseUnknownInCatchCallbackVariable; + +declare_oxc_lint!( + /// ### What it does + /// + /// This rule enforces using `unknown` for catch clause variables instead of `any`. + /// + /// ### Why is this bad? + /// + /// In TypeScript 4.0+, catch clause variables can be typed as `unknown` instead of `any`. Using `unknown` is safer because it forces you to perform type checking before using the error, preventing potential runtime errors. + /// + /// ### Examples + /// + /// Examples of **incorrect** code for this rule: + /// ```ts + /// try { + /// somethingRisky(); + /// } catch (error: any) { // Should use 'unknown' + /// console.log(error.message); // Unsafe access + /// error.someMethod(); // Unsafe call + /// } + /// + /// // Default catch variable is 'any' in older TypeScript + /// try { + /// somethingRisky(); + /// } catch (error) { // Implicitly 'any' + /// console.log(error.message); // Unsafe access + /// } + /// ``` + /// + /// Examples of **correct** code for this rule: + /// ```ts + /// try { + /// somethingRisky(); + /// } catch (error: unknown) { + /// // Type guard for Error objects + /// if (error instanceof Error) { + /// console.log(error.message); // Safe access + /// console.log(error.stack); + /// } else { + /// console.log('Unknown error:', error); + /// } + /// } + /// + /// // More comprehensive error handling + /// try { + /// somethingRisky(); + /// } catch (error: unknown) { + /// if (error instanceof Error) { + /// // Handle Error objects + /// console.error('Error:', error.message); + /// } else if (typeof error === 'string') { + /// // Handle string errors + /// console.error('String error:', error); + /// } else { + /// // Handle unknown error types + /// console.error('Unknown error type:', error); + /// } + /// } + /// + /// // Helper function for error handling + /// function isError(error: unknown): error is Error { + /// return error instanceof Error; + /// } + /// + /// try { + /// somethingRisky(); + /// } catch (error: unknown) { + /// if (isError(error)) { + /// console.log(error.message); + /// } + /// } + /// ``` + UseUnknownInCatchCallbackVariable(tsgolint), + typescript, + restriction, + pending, +); + +impl Rule for UseUnknownInCatchCallbackVariable {}