[QRQC_2] No implicitAny in twenty-server (#12075)

# Introduction
Following https://github.com/twentyhq/twenty/pull/12068
Related with https://github.com/twentyhq/core-team-issues/issues/975

We're enabling `noImplicitAny` handled few use case manually, added a
`ts-expect-error` to the others, we should plan to handle them in the
future
This commit is contained in:
Paul Rastoin
2025-05-15 18:23:22 +02:00
committed by GitHub
parent 08ce2f831e
commit 442f8dbe3c
120 changed files with 331 additions and 50 deletions

View File

@ -127,6 +127,7 @@ export class AdminPanelHealthService {
if (indicatorId === HealthIndicatorId.worker) {
return {
...indicatorStatus,
// @ts-expect-error legacy noImplicitAny
queues: (indicatorStatus?.queues ?? []).map((queue) => ({
id: `${indicatorId}-${queue.queueName}`,
queueName: queue.queueName,

View File

@ -201,14 +201,18 @@ export class AdminPanelService {
);
const versions = response.data.results
// @ts-expect-error legacy noImplicitAny
.filter((tag) => tag && tag.name !== 'latest')
// @ts-expect-error legacy noImplicitAny
.map((tag) => semver.coerce(tag.name)?.version)
// @ts-expect-error legacy noImplicitAny
.filter((version) => version !== undefined);
if (versions.length === 0) {
return { currentVersion, latestVersion: 'latest' };
}
// @ts-expect-error legacy noImplicitAny
versions.sort((a, b) => semver.compare(b, a));
const latestVersion = versions[0];

View File

@ -33,6 +33,7 @@ export class JwtAuthStrategy extends PassportStrategy(Strategy, 'jwt') {
private readonly userWorkspaceRepository: Repository<UserWorkspace>,
) {
const jwtFromRequestFunction = jwtWrapperService.extractJwtFromRequest();
// @ts-expect-error legacy noImplicitAny
const secretOrKeyProviderFunction = async (_request, rawJwtToken, done) => {
try {
const decodedToken = jwtWrapperService.decode(

View File

@ -24,6 +24,7 @@ export const transformStripeSubscriptionEventToDatabaseSubscription = (
currentPeriodStart: getDateFromTimestamp(data.object.current_period_start),
metadata: data.object.metadata,
collectionMethod:
// @ts-expect-error legacy noImplicitAny
BillingSubscriptionCollectionMethod[
data.object.collection_method.toUpperCase()
],

View File

@ -21,8 +21,10 @@ export class CloudflareSecretMatchGuard implements CanActivate {
if (
!cloudflareWebhookSecret ||
(cloudflareWebhookSecret &&
// @ts-expect-error legacy noImplicitAny
(typeof request.headers['cf-webhook-auth'] === 'string' ||
timingSafeEqual(
// @ts-expect-error legacy noImplicitAny
Buffer.from(request.headers['cf-webhook-auth']),
Buffer.from(cloudflareWebhookSecret),
)))

View File

@ -18,6 +18,7 @@ describe('DomainManagerService', () => {
FRONTEND_URL: 'https://example.com',
};
// @ts-expect-error legacy noImplicitAny
return env[key];
});
@ -42,6 +43,7 @@ describe('DomainManagerService', () => {
IS_MULTIWORKSPACE_ENABLED: true,
};
// @ts-expect-error legacy noImplicitAny
return env[key];
});
@ -91,6 +93,7 @@ describe('DomainManagerService', () => {
FRONTEND_URL: 'https://example.com',
};
// @ts-expect-error legacy noImplicitAny
return env[key];
});
@ -109,6 +112,7 @@ describe('DomainManagerService', () => {
DEFAULT_SUBDOMAIN: 'test',
};
// @ts-expect-error legacy noImplicitAny
return env[key];
});
@ -129,6 +133,7 @@ describe('DomainManagerService', () => {
DEFAULT_SUBDOMAIN: 'default',
};
// @ts-expect-error legacy noImplicitAny
return env[key];
});
@ -151,6 +156,7 @@ describe('DomainManagerService', () => {
FRONTEND_URL: 'https://example.com',
};
// @ts-expect-error legacy noImplicitAny
return env[key];
});
@ -174,6 +180,7 @@ describe('DomainManagerService', () => {
FRONTEND_URL: 'https://example.com',
};
// @ts-expect-error legacy noImplicitAny
return env[key];
});

View File

@ -13,6 +13,7 @@ export const objectRecordChangedProperties = <
newRecord: PRecord,
) => {
const changedProperties = Object.keys(newRecord).filter(
// @ts-expect-error legacy noImplicitAny
(key) => !deepEqual(oldRecord[key], newRecord[key]),
);

View File

@ -15,6 +15,7 @@ export const useSentryTracing = <
onExecute({ args }) {
const transactionName = args.operationName || 'Anonymous Operation';
const rootOperation = args.document.definitions.find(
// @ts-expect-error legacy noImplicitAny
(o) => o.kind === Kind.OPERATION_DEFINITION,
) as OperationDefinitionNode;
const operationType = rootOperation.operation;

View File

@ -212,6 +212,7 @@ describe('FeatureFlagService', () => {
// Assert
expect(result).toEqual(mockFeatureFlag);
expect(mockFeatureFlagRepository.save).toHaveBeenCalledWith({
// @ts-expect-error legacy noImplicitAny
key: FeatureFlagKey[featureFlag],
value,
workspaceId,

View File

@ -99,6 +99,7 @@ export class FeatureFlagService {
),
);
// @ts-expect-error legacy noImplicitAny
const featureFlagKey = FeatureFlagKey[featureFlag];
if (shouldBePublic) {

View File

@ -7,6 +7,7 @@ const assertIsFeatureFlagKey = (
featureFlagKey: string,
exceptionToThrow: CustomException,
): asserts featureFlagKey is FeatureFlagKey => {
// @ts-expect-error legacy noImplicitAny
if (isDefined(FeatureFlagKey[featureFlagKey])) return;
throw exceptionToThrow;
};

View File

@ -67,6 +67,7 @@ export class S3Driver implements StorageDriver {
await this.s3Client.send(command);
}
// @ts-expect-error legacy noImplicitAny
private async emptyS3Directory(folderPath) {
const listParams = {
Bucket: this.bucketName,

View File

@ -40,6 +40,7 @@ export class FileController {
@Req() req: Request,
) {
const folderPath = checkFilePath(params[0]);
// @ts-expect-error legacy noImplicitAny
const filename = checkFilename(params['filename']);
// eslint-disable-next-line @typescript-eslint/no-explicit-any

View File

@ -26,6 +26,7 @@ export const checkFilePath = (filePath: string): string => {
if (
folder !== kebabCase(FileFolder.ServerlessFunction) &&
size &&
// @ts-expect-error legacy noImplicitAny
!settings.storage.imageCropSizes[folder]?.includes(size)
) {
throw new BadRequestException(`Size ${size} is not allowed`);

View File

@ -54,6 +54,7 @@ export const useGraphQLErrorHandlerHook = <
async onExecute({ args }) {
const exceptionHandlerService = options.exceptionHandlerService;
const rootOperation = args.document.definitions.find(
// @ts-expect-error legacy noImplicitAny
(o) => o.kind === Kind.OPERATION_DEFINITION,
) as OperationDefinitionNode;

View File

@ -75,6 +75,7 @@ export class KeyValuePairService<
const conflictPaths = Object.keys(upsertData).filter(
(key) =>
['userId', 'workspaceId', 'key'].includes(key) &&
// @ts-expect-error legacy noImplicitAny
upsertData[key] !== undefined,
);

View File

@ -14,11 +14,13 @@ export interface MessageQueueDriver {
data: T,
options?: QueueJobOptions,
): Promise<void>;
// @ts-expect-error legacy noImplicitAny
work<T extends MessageQueueJobData>(
queueName: MessageQueue,
handler: ({ data, id }: { data: T; id: string }) => Promise<void> | void,
options?: MessageQueueWorkerOptions,
);
// @ts-expect-error legacy noImplicitAny
addCron<T extends MessageQueueJobData | undefined>({
queueName,
jobName,
@ -32,6 +34,7 @@ export interface MessageQueueDriver {
options: QueueCronJobOptions;
jobId?: string;
});
// @ts-expect-error legacy noImplicitAny
removeCron({
queueName,
jobName,

View File

@ -148,6 +148,7 @@ export class MessageQueueExplorer implements OnModuleInit {
const filteredProcessMethodNames = processMethodNames.filter(
(processMethodName) => {
const metadata = this.metadataAccessor.getProcessMetadata(
// @ts-expect-error legacy noImplicitAny
instance[processMethodName],
);
@ -203,6 +204,7 @@ export class MessageQueueExplorer implements OnModuleInit {
) {
for (const processMethodName of processMethodNames) {
try {
// @ts-expect-error legacy noImplicitAny
await instance[processMethodName].call(instance, job.data);
} catch (err) {
if (!shouldFilterException(err)) {

View File

@ -156,9 +156,12 @@ export class TimelineMessagingService {
if (!threadParticipant.message.messageThreadId)
return threadParticipantsAcc;
// @ts-expect-error legacy noImplicitAny
if (!threadParticipantsAcc[threadParticipant.message.messageThreadId])
// @ts-expect-error legacy noImplicitAny
threadParticipantsAcc[threadParticipant.message.messageThreadId] = [];
// @ts-expect-error legacy noImplicitAny
threadParticipantsAcc[threadParticipant.message.messageThreadId].push(
threadParticipant,
);
@ -248,6 +251,7 @@ export class TimelineMessagingService {
[key: string]: MessageChannelVisibility;
} = messageThreadIds.reduce((threadVisibilityAcc, messageThreadId) => {
// If the workspace member is not the owner of the thread, use the visibility value from the query
// @ts-expect-error legacy noImplicitAny
threadVisibilityAcc[messageThreadId] =
threadIdsWithoutWorkspaceMember.includes(messageThreadId)
? (threadVisibilityByThreadIdForWhichWorkspaceMemberIsNotOwner?.[

View File

@ -258,7 +258,9 @@ export class SearchService {
}
return (
// @ts-expect-error legacy noImplicitAny
(STANDARD_OBJECTS_BY_PRIORITY_RANK[b.objectNameSingular] || 0) -
// @ts-expect-error legacy noImplicitAny
(STANDARD_OBJECTS_BY_PRIORITY_RANK[a.objectNameSingular] || 0)
);
});

View File

@ -1,6 +1,7 @@
import fs from 'fs';
import { pipeline } from 'stream/promises';
// @ts-expect-error legacy noImplicitAny
import archiver from 'archiver';
export const createZipFile = async (

View File

@ -15,6 +15,7 @@ export class ConsoleListener {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
intercept(callback: (type: string, message: any[]) => void) {
Object.keys(this.originalConsole).forEach((method) => {
// @ts-expect-error legacy noImplicitAny
// eslint-disable-next-line @typescript-eslint/no-explicit-any
console[method] = (...args: any[]) => {
callback(method, args);
@ -24,8 +25,10 @@ export class ConsoleListener {
release() {
Object.keys(this.originalConsole).forEach((method) => {
// @ts-expect-error legacy noImplicitAny
// eslint-disable-next-line @typescript-eslint/no-explicit-any
console[method] = (...args: any[]) => {
// @ts-expect-error legacy noImplicitAny
this.originalConsole[method](...args);
};
});

View File

@ -3,8 +3,7 @@ import { Transform } from 'class-transformer';
export const CastToPositiveNumber = () =>
Transform(({ value }: { value: string }) => toNumber(value));
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const toNumber = (value: any) => {
const toNumber = (value: unknown): number | undefined => {
if (typeof value === 'number') {
return value >= 0 ? value : undefined;
}

View File

@ -382,6 +382,7 @@ describe('TwentyConfigService', () => {
SENSITIVE_VAR: 'sensitive_data_123',
};
// @ts-expect-error legacy noImplicitAny
return values[keyStr] || undefined;
});
@ -390,6 +391,7 @@ describe('TwentyConfigService', () => {
.mockImplementation((key: keyof ConfigVariables) => {
const keyStr = String(key);
// @ts-expect-error legacy noImplicitAny
if (mockConfigVarMetadata[keyStr]?.isEnvOnly) {
return environmentConfigDriver.get(key);
}
@ -398,6 +400,7 @@ describe('TwentyConfigService', () => {
SENSITIVE_VAR: 'sensitive_data_123',
};
// @ts-expect-error legacy noImplicitAny
return values[keyStr] || undefined;
});
};

View File

@ -64,12 +64,14 @@ describe('applyBasicValidators', () => {
const mockTransformParams = { value: 'true' };
(configTransformers.boolean as jest.Mock).mockReturnValueOnce(true);
// @ts-expect-error legacy noImplicitAny
const result1 = transformFn(mockTransformParams);
expect(configTransformers.boolean).toHaveBeenCalledWith('true');
expect(result1).toBe(true);
(configTransformers.boolean as jest.Mock).mockReturnValueOnce(undefined);
// @ts-expect-error legacy noImplicitAny
const result2 = transformFn(mockTransformParams);
expect(result2).toBe('true');
@ -99,12 +101,14 @@ describe('applyBasicValidators', () => {
const mockTransformParams = { value: '42' };
(configTransformers.number as jest.Mock).mockReturnValueOnce(42);
// @ts-expect-error legacy noImplicitAny
const result1 = transformFn(mockTransformParams);
expect(configTransformers.number).toHaveBeenCalledWith('42');
expect(result1).toBe(42);
(configTransformers.number as jest.Mock).mockReturnValueOnce(undefined);
// @ts-expect-error legacy noImplicitAny
const result2 = transformFn(mockTransformParams);
expect(result2).toBe('42');

View File

@ -35,8 +35,10 @@ describe('mergeUserVars', () => {
});
it('should merge user vars correctly when user vars are empty', () => {
// @ts-expect-error legacy noImplicitAny
const userVars = [];
// @ts-expect-error legacy noImplicitAny
const mergedUserVars = mergeUserVars(userVars);
expect(mergedUserVars).toEqual(new Map());

View File

@ -129,11 +129,15 @@ export class UserResolver {
const grantedSettingsPermissions: SettingPermissionType[] = (
Object.keys(settingsPermissions) as SettingPermissionType[]
).filter((feature) => settingsPermissions[feature] === true);
)
// @ts-expect-error legacy noImplicitAny
.filter((feature) => settingsPermissions[feature] === true);
const grantedObjectRecordsPermissions = (
Object.keys(objectRecordsPermissions) as PermissionsOnAllObjectRecords[]
).filter((permission) => objectRecordsPermissions[permission] === true);
)
// @ts-expect-error legacy noImplicitAny
.filter((permission) => objectRecordsPermissions[permission] === true);
currentUserWorkspace.settingsPermissions = grantedSettingsPermissions;
currentUserWorkspace.objectRecordsPermissions =