Skip to content

Commit ff47500

Browse files
fix: replace 'any' types with proper TypeScript types (fixes #1265)
TYPE SAFETY FIX - Phase 1: Critical Paths Issue: #1265 Problem: Widespread use of 'any' type across codebase (30+ occurrences) causing: - No IDE autocomplete or type checking - Runtime errors not caught at compile time - Refactoring breaks silently - Difficult to trace data flow - Production runtime errors Phase 1 Changes (Critical Paths): This commit addresses the most critical type safety issues in core authentication and API packages. New Type Definitions: - packages/api/src/types.ts - Message, User, ActionData, UiInteractionData - packages/auth/src/types.ts - CurrentUser, AuthToken Fixed Files: - packages/api/src/cloneArray.ts • Use generic type <T extends Record<string, unknown>> • Properly typed cloning function - packages/api/src/EmbeddedChatApi.ts • onMessageCallbacks: Message type instead of any • onActionTriggeredCallbacks: ActionData instead of any • onUiInteractionCallbacks: UiInteractionData instead of any - packages/auth/src/RocketChatAuth.ts • currentUser: CurrentUser | null instead of any • authListeners: Properly typed callbacks - packages/auth/src/Api.ts • request() data parameter: unknown instead of any • ApiError constructor: unknown[] instead of any[] - packages/rc-app/lib/getCallbackContent.ts • config: CallbackConfig interface instead of any • error parameter: optional string type Exported Types: - packages/api/src/index.ts - Export all types - packages/auth/src/index.ts - Export all types Impact: ✅ Type safety in critical authentication paths ✅ IDE autocomplete for message callbacks ✅ Compile-time error detection ✅ Better refactoring support ✅ Clearer data flow Next Phase: - Remaining packages (24+ files) - Additional interfaces for complex types - Stricter tsconfig settings Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 6e57549 commit ff47500

9 files changed

Lines changed: 114 additions & 16 deletions

File tree

packages/api/src/EmbeddedChatApi.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,19 @@ import {
66
RocketChatAuth,
77
ApiError,
88
} from "@embeddedchat/auth";
9+
import { Message, ActionData, UiInteractionData } from "./types";
910

1011
// mutliple typing status can come at the same time they should be processed in order.
1112
let typingHandlerLock = 0;
1213
export default class EmbeddedChatApi {
1314
host: string;
1415
rid: string;
1516
rcClient: Rocketchat;
16-
onMessageCallbacks: ((message: any) => void)[];
17+
onMessageCallbacks: ((message: Message) => void)[];
1718
onMessageDeleteCallbacks: ((messageId: string) => void)[];
1819
onTypingStatusCallbacks: ((users: string[]) => void)[];
19-
onActionTriggeredCallbacks: ((data: any) => void)[];
20-
onUiInteractionCallbacks: ((data: any) => void)[];
20+
onActionTriggeredCallbacks: ((data: ActionData) => void)[];
21+
onUiInteractionCallbacks: ((data: UiInteractionData) => void)[];
2122
typingUsers: string[];
2223
auth: RocketChatAuth;
2324

packages/api/src/cloneArray.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
/**
2-
* Deep Cloning upto 2 levels
3-
* @param {*} array
4-
* @returns
2+
* Deep Cloning up to 2 levels
3+
* @param array - Array to clone
4+
* @returns Cloned array
55
*/
6-
const cloneArray = (array: any[]) => {
6+
const cloneArray = <T extends Record<string, unknown>>(array: T[]): T[] => {
77
const newArray = [...array].map((item) =>
8-
typeof item === "object" ? { ...item } : item
8+
typeof item === "object" && item !== null ? ({ ...item } as T) : item
99
);
1010
return newArray;
1111
};

packages/api/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export { default as EmbeddedChatApi } from "./EmbeddedChatApi";
2+
export * from "./types";

packages/api/src/types.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/**
2+
* Type definitions for EmbeddedChat API
3+
* Issue #1265: Replace 'any' types with proper TypeScript types
4+
*/
5+
6+
export interface User {
7+
_id: string;
8+
username: string;
9+
name?: string;
10+
status?: string;
11+
statusText?: string;
12+
avatarETag?: string;
13+
}
14+
15+
export interface MessageUser {
16+
_id: string;
17+
username: string;
18+
name?: string;
19+
}
20+
21+
export interface Attachment {
22+
title?: string;
23+
description?: string;
24+
title_link?: string;
25+
image_url?: string;
26+
audio_url?: string;
27+
video_url?: string;
28+
type?: string;
29+
[key: string]: unknown;
30+
}
31+
32+
export interface Message {
33+
_id: string;
34+
rid: string;
35+
msg: string;
36+
ts: Date | string;
37+
u: MessageUser;
38+
attachments?: Attachment[];
39+
mentions?: MessageUser[];
40+
channels?: string[];
41+
editedBy?: MessageUser;
42+
editedAt?: Date | string;
43+
[key: string]: unknown; // Allow additional fields from RocketChat
44+
}
45+
46+
export interface ActionData {
47+
actionId: string;
48+
value?: string;
49+
blockId?: string;
50+
appId?: string;
51+
[key: string]: unknown;
52+
}
53+
54+
export interface UiInteractionData {
55+
type: string;
56+
triggerId?: string;
57+
payload?: unknown;
58+
[key: string]: unknown;
59+
}

packages/auth/src/Api.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export class ApiError extends Error {
44
response: Response,
55
message?: string | undefined,
66
options?: ErrorOptions | undefined,
7-
...other: any[]
7+
...other: unknown[]
88
) {
99
super(message, options, ...(other as []));
1010
this.response = response;
@@ -30,7 +30,7 @@ export class Api {
3030
async request(
3131
method: string = "GET",
3232
endpoint: string,
33-
data: any,
33+
data: unknown,
3434
config: RequestInit
3535
) {
3636
const url = new URL(endpoint, this.baseUrl).toString();

packages/auth/src/RocketChatAuth.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@ import { IRocketChatAuthOptions } from "./IRocketChatAuthOptions";
55
import { Api, ApiError } from "./Api";
66
import loginWithRocketChatOAuth from "./loginWithRocketChatOAuth";
77
import handleSecureLogin from "./handleSecureLogin";
8+
import { CurrentUser } from "./types";
9+
810
class RocketChatAuth {
911
host: string;
1012
api: Api;
11-
currentUser: any;
13+
currentUser: CurrentUser | null;
1214
lastFetched: Date;
13-
authListeners: ((user: object | null) => void)[] = [];
15+
authListeners: ((user: CurrentUser | null) => void)[] = [];
1416
deleteToken: () => Promise<void>;
1517
saveToken: (token: string) => Promise<void>;
1618
getToken: () => Promise<string>;

packages/auth/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ export * from "./auth";
22
export { default as RocketChatAuth } from "./RocketChatAuth";
33
export * from "./IRocketChatAuthOptions";
44
export { ApiError } from "./Api";
5+
export * from "./types";

packages/auth/src/types.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* Type definitions for RocketChat Authentication
3+
* Issue #1265: Replace 'any' types with proper TypeScript types
4+
*/
5+
6+
export interface AuthToken {
7+
authToken: string;
8+
userId: string;
9+
}
10+
11+
export interface CurrentUser {
12+
_id: string;
13+
username: string;
14+
name?: string;
15+
status?: string;
16+
statusConnection?: string;
17+
utcOffset?: number;
18+
active?: boolean;
19+
roles?: string[];
20+
emails?: Array<{ address: string; verified: boolean }>;
21+
authToken?: string;
22+
[key: string]: unknown; // Allow additional fields
23+
}

packages/rc-app/lib/getCallbackContent.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,26 @@ interface ICredentials {
77
serviceName: string;
88
}
99

10+
interface CallbackConfig {
11+
success: boolean;
12+
error?: string;
13+
origin?: string;
14+
credentials?: {
15+
accessToken: string;
16+
expiresIn: number;
17+
serviceName: string;
18+
};
19+
}
20+
1021
export const getCallbackContent = async (
1122
read: IRead,
1223
credentials: ICredentials | null,
1324
origin: string,
14-
error
25+
error?: string
1526
) => {
1627
const { accessToken, expiresIn = 3600, serviceName } = credentials || {};
1728
const isAllowed = await isAllowedOrigin(read, origin);
18-
let config: any = {};
29+
let config: CallbackConfig;
1930
if (error) {
2031
config = {
2132
success: false,
@@ -31,9 +42,9 @@ export const getCallbackContent = async (
3142
success: true,
3243
origin,
3344
credentials: {
34-
accessToken,
45+
accessToken: accessToken!,
3546
expiresIn,
36-
serviceName,
47+
serviceName: serviceName!,
3748
},
3849
};
3950
}

0 commit comments

Comments
 (0)