Skip to content

Commit fce1374

Browse files
dlabajclaude
andcommitted
fix: Replace 'any' types with proper TypeScript types
- Replace all 'any' types with 'unknown' or specific interfaces - Add GitHubIssue, GitHubComment, and ReactFiber interfaces - Add ReactComponentType interface for React internals - Fix linting issues: import sorting, unused variables - Remove unused parameters in test mocks - Add proper type narrowing for GitHub API responses - All CI checks now passing (type-check, lint, tests) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent a08dfe2 commit fce1374

8 files changed

Lines changed: 132 additions & 89 deletions

File tree

demo/src/test/setup.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ global.ResizeObserver = class ResizeObserver {
2121
observe = vi.fn();
2222
unobserve = vi.fn();
2323
disconnect = vi.fn();
24-
constructor(callback: ResizeObserverCallback) {}
24+
constructor() {}
2525
};
2626

2727
// Mock IntersectionObserver
2828
global.IntersectionObserver = class IntersectionObserver {
2929
observe = vi.fn();
3030
unobserve = vi.fn();
3131
disconnect = vi.fn();
32-
constructor(callback: IntersectionObserverCallback, options?: IntersectionObserverInit) {}
33-
} as any;
32+
constructor() {}
33+
} as unknown as typeof IntersectionObserver;

src/commenting-system/components/CommentOverlay.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,10 @@ export const CommentOverlay: React.FunctionComponent = () => {
158158
// Only use component name if this element IS a React component (not native)
159159
if (type && typeof type !== 'string') {
160160
const componentName = getComponentName(fiber);
161-
const displayName = (typeof type === 'function' && (type.displayName || type.name)) ||
162-
(type?.$$typeof === Symbol.for('react.forward_ref') && (type.render?.displayName || type.render?.name)) ||
161+
const componentTypeObj = type as { $$typeof?: symbol; render?: { displayName?: string; name?: string } };
162+
const fn = type as { displayName?: string; name?: string };
163+
const displayName = (typeof type === 'function' && (fn.displayName || fn.name)) ||
164+
(componentTypeObj?.$$typeof === Symbol.for('react.forward_ref') && (componentTypeObj.render?.displayName || componentTypeObj.render?.name)) ||
163165
undefined;
164166
previewName = componentName || displayName || elementDescription;
165167
}

src/commenting-system/contexts/CommentContext.tsx

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -442,18 +442,12 @@ export const CommentProvider: React.FunctionComponent<{ children: React.ReactNod
442442
const issueUrl = issue?.html_url as string | undefined;
443443
if (!issueNumber) continue;
444444

445-
const metadata = parseMetadataFromIssueBody(issue?.body || '');
445+
const metadata = parseMetadataFromIssueBody((issue?.body as string) || '');
446446

447447
const commentsResult = await githubAdapter.fetchIssueComments(issueNumber);
448448
const ghComments = commentsResult.success && commentsResult.data ? commentsResult.data : [];
449449

450-
const mappedComments: Comment[] = (Array.isArray(ghComments) ? ghComments : []).map(
451-
(c: {
452-
id: number;
453-
body?: string;
454-
user?: { login?: string };
455-
created_at?: string;
456-
}) => {
450+
const mappedComments: Comment[] = (Array.isArray(ghComments) ? ghComments : []).map((c) => {
457451
const rawBody = c?.body || '';
458452
return {
459453
id: `ghc-${c.id}`,
@@ -469,8 +463,8 @@ export const CommentProvider: React.FunctionComponent<{ children: React.ReactNod
469463
for (const c of mappedComments) {
470464
if (c.parentGitHubCommentId) continue;
471465
const raw = (Array.isArray(ghComments) ? ghComments : []).find(
472-
(x: { id?: number; body?: string }) => x?.id === c.githubCommentId,
473-
)?.body || '';
466+
(x) => x?.id === c.githubCommentId,
467+
)?.body as string || '';
474468
const inferred = inferReplyParentFromQuote(raw, mappedComments);
475469
if (inferred && inferred !== c.githubCommentId) {
476470
c.parentGitHubCommentId = inferred;

src/commenting-system/services/githubAdapter.ts

Lines changed: 69 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,27 @@ export const diagnoseGitHubSetup = () => {
6565
};
6666
};
6767

68-
export interface GitHubResult<T = any> {
68+
interface GitHubApiResponse {
69+
[key: string]: unknown;
70+
}
71+
72+
export interface GitHubIssue extends GitHubApiResponse {
73+
number: number;
74+
title?: string;
75+
state?: string;
76+
html_url?: string;
77+
body?: string;
78+
labels?: unknown[];
79+
}
80+
81+
export interface GitHubComment extends GitHubApiResponse {
82+
id: number;
83+
body?: string;
84+
user?: { login?: string };
85+
created_at?: string;
86+
}
87+
88+
export interface GitHubResult<T = GitHubApiResponse> {
6989
success: boolean;
7090
data?: T;
7191
error?: string;
@@ -81,7 +101,7 @@ export interface GitHubIssueSummary {
81101
labels: unknown[];
82102
}
83103

84-
async function githubProxyRequest(method: string, endpoint: string, data?: any): Promise<any> {
104+
async function githubProxyRequest(method: string, endpoint: string, data?: unknown): Promise<GitHubApiResponse> {
85105
const token = getStoredToken();
86106
if (!token) {
87107
throw new Error('Not authenticated with GitHub');
@@ -141,18 +161,18 @@ const base64DecodeUtf8 = (input: string): string => {
141161
return decodeURIComponent(escape(atob(input)));
142162
};
143163

144-
const getLabelNames = (issue: any): string[] => {
164+
const getLabelNames = (issue: GitHubApiResponse): string[] => {
145165
const labels = issue?.labels;
146166
if (!Array.isArray(labels)) return [];
147167
return labels
148-
.map((l: any) => (typeof l === 'string' ? l : l?.name))
149-
.filter((n: any) => typeof n === 'string');
168+
.map((l: unknown) => (typeof l === 'string' ? l : (l as Record<string, unknown>)?.name))
169+
.filter((n: unknown): n is string => typeof n === 'string');
150170
};
151171

152-
const issueHasAnyVersion = (issue: any): boolean => {
172+
const issueHasAnyVersion = (issue: GitHubApiResponse): boolean => {
153173
const labelNames = getLabelNames(issue);
154174
if (labelNames.some((n) => n.startsWith('version:'))) return true;
155-
const body: string = issue?.body || '';
175+
const body: string = (issue?.body as string) || '';
156176
return body.includes('Version:');
157177
};
158178

@@ -206,26 +226,26 @@ export const githubAdapter = {
206226
// ignore label failures
207227
}
208228

209-
return { success: true, data };
210-
} catch (e: any) {
211-
return { success: false, error: e?.message || 'Failed to create issue' };
229+
return { success: true, data: data as { number: number; html_url: string } };
230+
} catch (e: unknown) {
231+
return { success: false, error: (e as Error)?.message || 'Failed to create issue' };
212232
}
213233
},
214234

215-
async createComment(issueNumber: number, body: string): Promise<GitHubResult> {
235+
async createComment(issueNumber: number, body: string): Promise<GitHubResult<GitHubApiResponse>> {
216236
if (!isGitHubConfigured()) return { success: false, error: 'Please sign in with GitHub' };
217237
const owner = getEnv('VITE_GITHUB_OWNER');
218238
const repo = getEnv('VITE_GITHUB_REPO');
219239

220240
try {
221241
const data = await githubProxyRequest('POST', `/repos/${owner}/${repo}/issues/${issueNumber}/comments`, { body });
222242
return { success: true, data };
223-
} catch (e: any) {
224-
return { success: false, error: e?.message || 'Failed to create comment' };
243+
} catch (e: unknown) {
244+
return { success: false, error: (e as Error)?.message || 'Failed to create comment' };
225245
}
226246
},
227247

228-
async fetchIssuesForRoute(route: string): Promise<GitHubResult<any[]>> {
248+
async fetchIssuesForRoute(route: string): Promise<GitHubResult<GitHubIssue[]>> {
229249
return githubAdapter.fetchIssuesForRouteAndVersion(route);
230250
},
231251

@@ -246,12 +266,12 @@ export const githubAdapter = {
246266
labels: Array.isArray(data.labels) ? data.labels : [],
247267
},
248268
};
249-
} catch (e: any) {
250-
return { success: false, error: e?.message || 'Failed to fetch issue' };
269+
} catch (e: unknown) {
270+
return { success: false, error: (e as Error)?.message || 'Failed to fetch issue' };
251271
}
252272
},
253273

254-
async fetchIssuesForRouteAndVersion(route: string, version?: string): Promise<GitHubResult<any[]>> {
274+
async fetchIssuesForRouteAndVersion(route: string, version?: string): Promise<GitHubResult<GitHubIssue[]>> {
255275
if (!isGitHubConfigured()) return { success: false, error: 'Please sign in with GitHub' };
256276
const owner = getEnv('VITE_GITHUB_OWNER');
257277
const repo = getEnv('VITE_GITHUB_REPO');
@@ -262,18 +282,18 @@ export const githubAdapter = {
262282
);
263283
// Filter by metadata OR labels (route:${route}), and optionally by version
264284
const filtered = (Array.isArray(data) ? data : [])
265-
.filter((issue: any) => {
266-
const body: string = issue?.body || '';
285+
.filter((issue: GitHubApiResponse) => {
286+
const body: string = (issue?.body as string) || '';
267287
const labels = getLabelNames(issue);
268288
const bodyMatch = body.includes(`Route: \`${route}\``);
269289
const labelMatch = labels.includes(`route:${route}`);
270290
return bodyMatch || labelMatch;
271291
})
272-
.filter((issue: any) => {
292+
.filter((issue: GitHubApiResponse) => {
273293
if (!version) return true;
274294

275295
const labels = getLabelNames(issue);
276-
const body: string = issue?.body || '';
296+
const body: string = (issue?.body as string) || '';
277297
const versionLabelMatch = labels.includes(`version:${version}`);
278298
const bodyVersionMatch = body.includes(`Version: \`${version}\``);
279299

@@ -282,13 +302,13 @@ export const githubAdapter = {
282302

283303
return versionLabelMatch || bodyVersionMatch;
284304
});
285-
return { success: true, data: filtered };
286-
} catch (e: any) {
287-
return { success: false, error: e?.message || 'Failed to fetch issues' };
305+
return { success: true, data: filtered as GitHubIssue[] };
306+
} catch (e: unknown) {
307+
return { success: false, error: (e as Error)?.message || 'Failed to fetch issues' };
288308
}
289309
},
290310

291-
async fetchIssueComments(issueNumber: number): Promise<GitHubResult<any[]>> {
311+
async fetchIssueComments(issueNumber: number): Promise<GitHubResult<GitHubComment[]>> {
292312
if (!isGitHubConfigured()) return { success: false, error: 'Please sign in with GitHub' };
293313
const owner = getEnv('VITE_GITHUB_OWNER');
294314
const repo = getEnv('VITE_GITHUB_REPO');
@@ -297,57 +317,57 @@ export const githubAdapter = {
297317
'GET',
298318
`/repos/${owner}/${repo}/issues/${issueNumber}/comments?per_page=100`,
299319
);
300-
return { success: true, data };
301-
} catch (e: any) {
302-
return { success: false, error: e?.message || 'Failed to fetch issue comments' };
320+
return { success: true, data: data as unknown as GitHubComment[] };
321+
} catch (e: unknown) {
322+
return { success: false, error: (e as Error)?.message || 'Failed to fetch issue comments' };
303323
}
304324
},
305325

306-
async updateComment(commentId: number, body: string): Promise<GitHubResult> {
326+
async updateComment(commentId: number, body: string): Promise<GitHubResult<GitHubApiResponse>> {
307327
if (!isGitHubConfigured()) return { success: false, error: 'Please sign in with GitHub' };
308328
const owner = getEnv('VITE_GITHUB_OWNER');
309329
const repo = getEnv('VITE_GITHUB_REPO');
310330
try {
311331
const data = await githubProxyRequest('PATCH', `/repos/${owner}/${repo}/issues/comments/${commentId}`, { body });
312332
return { success: true, data };
313-
} catch (e: any) {
314-
return { success: false, error: e?.message || 'Failed to update comment' };
333+
} catch (e: unknown) {
334+
return { success: false, error: (e as Error)?.message || 'Failed to update comment' };
315335
}
316336
},
317337

318-
async deleteComment(commentId: number): Promise<GitHubResult> {
338+
async deleteComment(commentId: number): Promise<GitHubResult<GitHubApiResponse>> {
319339
if (!isGitHubConfigured()) return { success: false, error: 'Please sign in with GitHub' };
320340
const owner = getEnv('VITE_GITHUB_OWNER');
321341
const repo = getEnv('VITE_GITHUB_REPO');
322342
try {
323343
await githubProxyRequest('DELETE', `/repos/${owner}/${repo}/issues/comments/${commentId}`);
324344
return { success: true, data: {} };
325-
} catch (e: any) {
326-
return { success: false, error: e?.message || 'Failed to delete comment' };
345+
} catch (e: unknown) {
346+
return { success: false, error: (e as Error)?.message || 'Failed to delete comment' };
327347
}
328348
},
329349

330-
async closeIssue(issueNumber: number): Promise<GitHubResult> {
350+
async closeIssue(issueNumber: number): Promise<GitHubResult<GitHubApiResponse>> {
331351
if (!isGitHubConfigured()) return { success: false, error: 'Please sign in with GitHub' };
332352
const owner = getEnv('VITE_GITHUB_OWNER');
333353
const repo = getEnv('VITE_GITHUB_REPO');
334354
try {
335355
const data = await githubProxyRequest('PATCH', `/repos/${owner}/${repo}/issues/${issueNumber}`, { state: 'closed' });
336356
return { success: true, data };
337-
} catch (e: any) {
338-
return { success: false, error: e?.message || 'Failed to close issue' };
357+
} catch (e: unknown) {
358+
return { success: false, error: (e as Error)?.message || 'Failed to close issue' };
339359
}
340360
},
341361

342-
async reopenIssue(issueNumber: number): Promise<GitHubResult> {
362+
async reopenIssue(issueNumber: number): Promise<GitHubResult<GitHubApiResponse>> {
343363
if (!isGitHubConfigured()) return { success: false, error: 'Please sign in with GitHub' };
344364
const owner = getEnv('VITE_GITHUB_OWNER');
345365
const repo = getEnv('VITE_GITHUB_REPO');
346366
try {
347367
const data = await githubProxyRequest('PATCH', `/repos/${owner}/${repo}/issues/${issueNumber}`, { state: 'open' });
348368
return { success: true, data };
349-
} catch (e: any) {
350-
return { success: false, error: e?.message || 'Failed to reopen issue' };
369+
} catch (e: unknown) {
370+
return { success: false, error: (e as Error)?.message || 'Failed to reopen issue' };
351371
}
352372
},
353373

@@ -357,17 +377,17 @@ export const githubAdapter = {
357377
const repo = getEnv('VITE_GITHUB_REPO');
358378
try {
359379
const data = await githubProxyRequest('GET', `/repos/${owner}/${repo}/contents/${encodePath(path)}`);
360-
const content = typeof data?.content === 'string' ? data.content.replace(/\n/g, '') : '';
361-
const sha = data?.sha as string | undefined;
380+
const content = typeof data.content === 'string' ? data.content.replace(/\n/g, '') : '';
381+
const sha = data.sha as string | undefined;
362382
if (!content || !sha) return { success: true, data: null };
363383
const text = base64DecodeUtf8(content);
364384
return { success: true, data: { text, sha } };
365-
} catch (e: any) {
385+
} catch (e: unknown) {
366386
// If file doesn't exist yet, treat as empty
367-
if (String(e?.message || '').toLowerCase().includes('not found')) {
387+
if (String((e as Error)?.message || '').toLowerCase().includes('not found')) {
368388
return { success: true, data: null };
369389
}
370-
return { success: false, error: e?.message || 'Failed to read repo file' };
390+
return { success: false, error: (e as Error)?.message || 'Failed to read repo file' };
371391
}
372392
},
373393

@@ -381,7 +401,7 @@ export const githubAdapter = {
381401
const owner = getEnv('VITE_GITHUB_OWNER');
382402
const repo = getEnv('VITE_GITHUB_REPO');
383403
try {
384-
const payload: any = {
404+
const payload: Record<string, string> = {
385405
message: params.message,
386406
content: base64EncodeUtf8(params.text),
387407
};
@@ -391,10 +411,10 @@ export const githubAdapter = {
391411
`/repos/${owner}/${repo}/contents/${encodePath(params.path)}`,
392412
payload,
393413
);
394-
const newSha = data?.content?.sha as string | undefined;
414+
const newSha = ((data as { content?: { sha?: string } }).content?.sha) as string | undefined;
395415
return { success: true, data: { sha: newSha || params.sha || '' } };
396-
} catch (e: any) {
397-
return { success: false, error: e?.message || 'Failed to write repo file' };
416+
} catch (e: unknown) {
417+
return { success: false, error: (e as Error)?.message || 'Failed to write repo file' };
398418
}
399419
},
400420
};

src/commenting-system/services/summarizeService.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { describe, expect, it, vi, afterEach } from 'vitest';
1+
import { afterEach, describe, expect, it, vi } from 'vitest';
22
import {
33
buildPromptForThread,
44
buildPromptForThreads,

0 commit comments

Comments
 (0)