Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

chore: enable noExplicitAny lint rule #824

Merged
merged 5 commits into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/pr-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jobs:

- run: pnpm format
if: always()
- run: pnpm lint
- run: pnpm lint --reporter=github
Copy link
Member Author

Choose a reason for hiding this comment

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

Shows up in GitHub like this:
image

if: always()
- run: pnpm typecheck
if: always()
Expand Down
1 change: 0 additions & 1 deletion biome.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
"noNonNullAssertion": "off" // TODO: turn on, too many cases
},
"suspicious": {
"noExplicitAny": "off", // TODO: turn on, too many cases
"noConsole": "warn"
},
"a11y": {
Expand Down
23 changes: 11 additions & 12 deletions src/background/services/deduplicator.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { Cradle } from '../container';

type AsyncFn<T> = (...args: any[]) => Promise<T>;
type AsyncFn<T> = (...args: unknown[]) => Promise<T>;

interface CacheEntry {
promise: Promise<any>;
interface CacheEntry<T> {
promise: Promise<T>;
}

interface DedupeOptions {
Expand All @@ -15,29 +15,29 @@ interface DedupeOptions {
export class Deduplicator {
private logger: Cradle['logger'];

private cache: Map<string, CacheEntry> = new Map();
private cache: Map<string, CacheEntry<unknown>> = new Map();

constructor({ logger }: Pick<Cradle, 'logger'>) {
Object.assign(this, { logger });
}

dedupe<T extends AsyncFn<any>>(
fn: T,
dedupe<T>(
fn: AsyncFn<T>,
{
cacheFnArgs = false,
cacheRejections = false,
wait = 5000,
}: Partial<DedupeOptions> = {},
): T {
return (async (...args: Parameters<T>): Promise<ReturnType<T>> => {
): AsyncFn<T> {
return async (...args: Parameters<typeof fn>): Promise<T> => {
const key = this.generateCacheKey(fn, args, cacheFnArgs);
const entry = this.cache.get(key);

if (entry) {
this.logger.debug(
`Deduplicating function=${fn.name}, ${cacheFnArgs ? `args=${JSON.stringify(args)}` : 'without args'}`,
);
return entry.promise as ReturnType<T>;
return entry.promise as Promise<T>;
}

const promise = fn(...args);
Expand All @@ -53,17 +53,16 @@ export class Deduplicator {
} else {
this.cache.delete(key);
}

return Promise.reject(err);
} finally {
this.scheduleCacheClear(key, wait);
}
}) as unknown as T;
};
}

private generateCacheKey<T>(
fn: AsyncFn<T>,
args: any[],
args: unknown[],
cacheFnArgs: boolean,
): string {
if (!fn.name) {
Expand Down
22 changes: 11 additions & 11 deletions src/background/services/openPayments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,28 +212,28 @@ export class OpenPaymentsService {
}
}

const isOpenPaymentsClientError = (error: any) =>
const isOpenPaymentsClientError = (error: unknown) =>
error instanceof OpenPaymentsClientError;

export const isKeyRevokedError = (error: any) => {
export const isKeyRevokedError = (error: unknown) => {
if (!isOpenPaymentsClientError(error)) return false;
return isInvalidClientError(error) || isSignatureValidationError(error);
};

// AUTH SERVER error
export const isInvalidClientError = (error: any) => {
export const isInvalidClientError = (error: unknown) => {
if (!isOpenPaymentsClientError(error)) return false;
return error.status === 400 && error.code === 'invalid_client';
};

export const isInvalidContinuationError = (error: any) => {
export const isInvalidContinuationError = (error: unknown) => {
if (!isOpenPaymentsClientError(error)) return false;
return error.status === 401 && error.code === 'invalid_continuation';
};

// RESOURCE SERVER error. Create outgoing payment and create quote can fail
// with: `Signature validation error: could not find key in list of client keys`
export const isSignatureValidationError = (error: any) => {
export const isSignatureValidationError = (error: unknown) => {
if (!isOpenPaymentsClientError(error)) return false;
return (
error.status === 401 &&
Expand All @@ -242,7 +242,7 @@ export const isSignatureValidationError = (error: any) => {
};

export const isTokenExpiredError = (
error: any,
error: unknown,
): error is OpenPaymentsClientError => {
if (!isOpenPaymentsClientError(error)) return false;
return isTokenInvalidError(error) || isTokenInactiveError(error);
Expand All @@ -255,20 +255,20 @@ export const isTokenInactiveError = (error: OpenPaymentsClientError) => {
};

// happens during quoting only
export const isNonPositiveAmountError = (error: any) => {
export const isNonPositiveAmountError = (error: unknown) => {
if (!isOpenPaymentsClientError(error)) return false;
return (
error.status === 400 &&
error.description?.toLowerCase()?.includes('non-positive receive amount')
);
};

export const isOutOfBalanceError = (error: any) => {
export const isOutOfBalanceError = (error: unknown) => {
if (!isOpenPaymentsClientError(error)) return false;
return error.status === 403 && error.description === 'unauthorized';
};

export const isMissingGrantPermissionsError = (error: any) => {
export const isMissingGrantPermissionsError = (error: unknown) => {
if (!isOpenPaymentsClientError(error)) return false;
// providers using Rafiki <= v1.0.0-alpha.15 show "Insufficient Grant" error,
// but Rafiki >= v1.0.0-alpha.16 shows "Inactive Token" (due to
Expand All @@ -279,12 +279,12 @@ export const isMissingGrantPermissionsError = (error: any) => {
);
};

export const isInvalidReceiverError = (error: any) => {
export const isInvalidReceiverError = (error: unknown) => {
if (!isOpenPaymentsClientError(error)) return false;
return error.status === 400 && error.description === 'invalid receiver';
};

export const isNotFoundError = (error: any) => {
export const isNotFoundError = (error: unknown) => {
if (!isOpenPaymentsClientError(error)) return false;
return error.status === 404;
};
7 changes: 4 additions & 3 deletions src/background/services/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,10 @@ export class StorageService {
/**
* @param existingData Existing data from previous version.
*/
type Migration = (
existingData: Record<string, any>,
) => [data: Record<string, any>, deleteKeys?: string[]];

// biome-ignore lint/suspicious/noExplicitAny: our code defines shape of data
type Data = Record<string, any>;
type Migration = (existingData: Data) => [data: Data, deleteKeys?: string[]];

// There was never a migration to reach 1.
//
Expand Down
2 changes: 1 addition & 1 deletion src/content/keyAutoAdd/lib/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,6 @@ class TimeoutError extends Error {
}
}

export function isTimedOut(e: any) {
export function isTimedOut(e: unknown) {
return e instanceof TimeoutError;
}
16 changes: 0 additions & 16 deletions src/content/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,3 @@ try {
export function mozClone<T = unknown>(obj: T, document: Document) {
return cloneIntoRef ? cloneIntoRef(obj, document.defaultView) : obj;
}

export class CustomError extends Error {
constructor(message?: string) {
// 'Error' breaks prototype chain here
super(message);

// restore prototype chain
const actualProto = new.target.prototype;

if (Object.setPrototypeOf) {
Object.setPrototypeOf(this, actualProto);
} else {
(this as any).__proto__ = actualProto;
}
}
}
2 changes: 1 addition & 1 deletion src/pages/shared/components/ui/RadioGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export interface RadioProps {
name: string;
id?: string;
disabled?: boolean;
onChange?: any;
onChange?: React.ChangeEventHandler<HTMLInputElement>;
noSelected?: boolean;
}

Expand Down
13 changes: 8 additions & 5 deletions src/pages/shared/lib/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,14 @@ export function useLocalStorage<T>(
maxAge *= 1000;

type Stored = { value: T; expiresAt: number };
const isWellFormed = React.useCallback((obj: any): obj is Stored => {
if (typeof obj !== 'object' || obj == null) return false;
if (!obj.expiresAt || !Number.isSafeInteger(obj.expiresAt)) return false;
return typeof obj.value !== 'undefined';
}, []);
const isWellFormed = React.useCallback(
(obj?: Record<string, unknown>): obj is Stored => {
if (typeof obj !== 'object' || obj == null) return false;
if (!obj.expiresAt || !Number.isSafeInteger(obj.expiresAt)) return false;
return typeof obj.value !== 'undefined';
},
[],
);

const [value, setValue] = React.useState<T>(() => {
if (!hasLocalStorage) return defaultValue;
Expand Down
9 changes: 6 additions & 3 deletions src/shared/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,14 @@ export const errorWithKey = <T extends ErrorKeys = ErrorKeys>(
cause?: ErrorWithKeyLike,
) => ({ key, substitutions, cause });

export const isErrorWithKey = (err: any): err is ErrorWithKeyLike => {
export const isErrorWithKey = (err: unknown): err is ErrorWithKeyLike => {
if (!err || typeof err !== 'object') return false;
if (err instanceof ErrorWithKey) return true;
return (
err instanceof ErrorWithKey ||
(typeof err.key === 'string' && Array.isArray(err.substitutions))
'key' in err &&
typeof err.key === 'string' &&
'substitutions' in err &&
Array.isArray(err.substitutions)
);
};

Expand Down
2 changes: 1 addition & 1 deletion tests/e2e/fixtures/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export const expect = test.expect.extend({
const name = 'toHaveStorage';

let pass: boolean;
let result: any;
let result: { actual: unknown } | undefined;

const storedData = await getStorage(
background,
Expand Down
4 changes: 2 additions & 2 deletions tests/e2e/fixtures/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ export const loadFirefoxAddon = (
type: 'getRoot',
});

const onMessage = (message: any) => {
if (message.addonsActor) {
const onMessage = (message: Record<string, unknown>) => {
if (message.addonsActor && typeof message.addonsActor === 'string') {
send({
to: message.addonsActor,
type: 'installTemporaryAddon',
Expand Down