diff --git a/packages/livechat/src/components/Messages/AudioAttachment/index.js b/packages/livechat/src/components/Messages/AudioAttachment/index.tsx
similarity index 83%
rename from packages/livechat/src/components/Messages/AudioAttachment/index.js
rename to packages/livechat/src/components/Messages/AudioAttachment/index.tsx
index c3dad7c80d6b0854b6779526cd6862290f3ebf83..78b6a6ee5923f4f86992b6e086763b8e570ed4ae 100644
--- a/packages/livechat/src/components/Messages/AudioAttachment/index.js
+++ b/packages/livechat/src/components/Messages/AudioAttachment/index.tsx
@@ -5,7 +5,13 @@ import { createClassName } from '../../../helpers/createClassName';
 import { MessageBubble } from '../MessageBubble';
 import styles from './styles.scss';
 
-const AudioAttachment = ({ url, className, t, ...messageBubbleProps }) => (
+type AudioAttachmentProps = {
+	url: string;
+	className?: string;
+	t: (key: string) => string;
+};
+
+const AudioAttachment = ({ url, className, t, ...messageBubbleProps }: AudioAttachmentProps) => (
 	<MessageBubble nude className={createClassName(styles, 'audio-attachment', {}, [className])} {...messageBubbleProps}>
 		<audio src={url} controls className={createClassName(styles, 'audio-attachment__inner')}>
 			{t('you_browser_doesn_t_support_audio_element')}
diff --git a/packages/livechat/src/components/Messages/FileAttachment/index.js b/packages/livechat/src/components/Messages/FileAttachment/index.tsx
similarity index 86%
rename from packages/livechat/src/components/Messages/FileAttachment/index.js
rename to packages/livechat/src/components/Messages/FileAttachment/index.tsx
index 303c9fc371736739ee4ef8e492d02e210bf7c3eb..3f97ca6289452eb5dbc61f5bb03026a56c2b8ea0 100644
--- a/packages/livechat/src/components/Messages/FileAttachment/index.js
+++ b/packages/livechat/src/components/Messages/FileAttachment/index.tsx
@@ -6,7 +6,13 @@ import { FileAttachmentIcon } from '../FileAttachmentIcon';
 import { MessageBubble } from '../MessageBubble';
 import styles from './styles.scss';
 
-export const FileAttachment = memo(({ url, title, className, ...messageBubbleProps }) => (
+type FileAttachmentProps = {
+	url: string;
+	title: string;
+	className?: string;
+};
+
+export const FileAttachment = memo(({ url, title, className, ...messageBubbleProps }: FileAttachmentProps) => (
 	<MessageBubble className={createClassName(styles, 'file-attachment', {}, [className])} {...messageBubbleProps}>
 		<a href={url} download target='_blank' rel='noopener noreferrer' className={createClassName(styles, 'file-attachment__inner')}>
 			<FileAttachmentIcon url={url} />
diff --git a/packages/livechat/src/components/Messages/FileAttachmentIcon/index.js b/packages/livechat/src/components/Messages/FileAttachmentIcon/index.tsx
similarity index 53%
rename from packages/livechat/src/components/Messages/FileAttachmentIcon/index.js
rename to packages/livechat/src/components/Messages/FileAttachmentIcon/index.tsx
index 9099d1f4aaf1c560e91b7fcbd95385ee1c055ba2..1ccef44d8e9f216d3739e61de47b97a5861685b1 100644
--- a/packages/livechat/src/components/Messages/FileAttachmentIcon/index.js
+++ b/packages/livechat/src/components/Messages/FileAttachmentIcon/index.tsx
@@ -7,15 +7,16 @@ import PPTIcon from '../../../icons/ppt.svg';
 import SheetIcon from '../../../icons/sheet.svg';
 import ZipIcon from '../../../icons/zip.svg';
 
-export const FileAttachmentIcon = memo(({ url }) => {
+export const FileAttachmentIcon = memo(({ url }: { url?: string }) => {
 	const extension = url ? url.split('.').pop() : null;
 
 	const Icon =
-		(/pdf/i.test(extension) && PDFIcon) ||
-		(/doc|docx|rtf|txt|odt|pages|log/i.test(extension) && DocIcon) ||
-		(/ppt|pptx|pps/i.test(extension) && PPTIcon) ||
-		(/xls|xlsx|csv/i.test(extension) && SheetIcon) ||
-		(/zip|rar|7z|gz/i.test(extension) && ZipIcon) ||
-		FileIcon;
+		extension &&
+		((/pdf/i.test(extension) && PDFIcon) ||
+			(/doc|docx|rtf|txt|odt|pages|log/i.test(extension) && DocIcon) ||
+			(/ppt|pptx|pps/i.test(extension) && PPTIcon) ||
+			(/xls|xlsx|csv/i.test(extension) && SheetIcon) ||
+			(/zip|rar|7z|gz/i.test(extension) && ZipIcon) ||
+			FileIcon);
 	return <Icon width={32} />;
 });
diff --git a/packages/livechat/src/components/Messages/ImageAttachment/index.js b/packages/livechat/src/components/Messages/ImageAttachment/index.tsx
similarity index 81%
rename from packages/livechat/src/components/Messages/ImageAttachment/index.js
rename to packages/livechat/src/components/Messages/ImageAttachment/index.tsx
index 23c60e24bc477ac8471c00f2c2f4fe3cd55c5fdd..f62817ebffbca7a0a7a3d63bd6866214530e6704 100644
--- a/packages/livechat/src/components/Messages/ImageAttachment/index.js
+++ b/packages/livechat/src/components/Messages/ImageAttachment/index.tsx
@@ -4,7 +4,12 @@ import { createClassName } from '../../../helpers/createClassName';
 import { MessageBubble } from '../MessageBubble';
 import styles from './styles.scss';
 
-export const ImageAttachment = memo(({ url, className, ...messageBubbleProps }) => (
+type ImageAttachmentProps = {
+	url: string;
+	className?: string;
+};
+
+export const ImageAttachment = memo(({ url, className, ...messageBubbleProps }: ImageAttachmentProps) => (
 	<MessageBubble nude className={createClassName(styles, 'image-attachment', {}, [className])} {...messageBubbleProps}>
 		<img src={url} className={createClassName(styles, 'image-attachment__inner')} />
 	</MessageBubble>
diff --git a/packages/livechat/src/components/Messages/MessageAvatars/index.js b/packages/livechat/src/components/Messages/MessageAvatars/index.tsx
similarity index 64%
rename from packages/livechat/src/components/Messages/MessageAvatars/index.js
rename to packages/livechat/src/components/Messages/MessageAvatars/index.tsx
index aa25528be11b0430d51373061e18908d3f158c58..9a405efb8ff030e429c7c58e28bda56eaf29316b 100644
--- a/packages/livechat/src/components/Messages/MessageAvatars/index.js
+++ b/packages/livechat/src/components/Messages/MessageAvatars/index.tsx
@@ -4,7 +4,14 @@ import { createClassName } from '../../../helpers/createClassName';
 import { Avatar } from '../../Avatar';
 import styles from './styles.scss';
 
-export const MessageAvatars = memo(({ avatarResolver = () => null, usernames = [], className, style = {} }) => {
+type MessageAvatarsProps = {
+	avatarResolver: (username: string) => string | undefined;
+	usernames: string[];
+	className?: string;
+	style?: React.CSSProperties;
+};
+
+export const MessageAvatars = memo(({ avatarResolver = () => undefined, usernames = [], className, style = {} }: MessageAvatarsProps) => {
 	const avatars = usernames.filter(Boolean);
 
 	if (!avatars.length) {
diff --git a/packages/livechat/src/components/Messages/MessageBlocks/index.js b/packages/livechat/src/components/Messages/MessageBlocks/index.tsx
similarity index 82%
rename from packages/livechat/src/components/Messages/MessageBlocks/index.js
rename to packages/livechat/src/components/Messages/MessageBlocks/index.tsx
index bccb1399b24b1295f9127e73123eefa3616e6185..d08b2360ebc2fdf0487df16ae746e7af8fc5674f 100644
--- a/packages/livechat/src/components/Messages/MessageBlocks/index.js
+++ b/packages/livechat/src/components/Messages/MessageBlocks/index.tsx
@@ -6,9 +6,15 @@ import { renderMessageBlocks } from '../../uiKit';
 import Surface from '../../uiKit/message/Surface';
 import styles from './styles.scss';
 
-const MessageBlocks = ({ blocks = [], mid = undefined, rid = undefined }) => {
+type MessageBlocksProps = {
+	blocks?: unknown[];
+	mid?: string;
+	rid?: string;
+};
+
+const MessageBlocks = ({ blocks = [], mid = undefined, rid = undefined }: MessageBlocksProps) => {
 	const dispatchAction = useCallback(
-		({ appId, actionId, payload }) =>
+		({ appId, actionId, payload }: { appId: string; actionId: string; payload: unknown }) =>
 			triggerAction({
 				appId,
 				type: UIKitIncomingInteractionType.BLOCK,
diff --git a/packages/livechat/src/components/Messages/MessageBubble/index.js b/packages/livechat/src/components/Messages/MessageBubble/index.tsx
similarity index 59%
rename from packages/livechat/src/components/Messages/MessageBubble/index.js
rename to packages/livechat/src/components/Messages/MessageBubble/index.tsx
index 56009164c170fad47304cb3227243fc5dedf789c..b46d28a8f8471e93b4186b5a2800e5a13aada93e 100644
--- a/packages/livechat/src/components/Messages/MessageBubble/index.js
+++ b/packages/livechat/src/components/Messages/MessageBubble/index.tsx
@@ -1,9 +1,20 @@
+import type { ComponentChildren } from 'preact';
 import { memo } from 'preact/compat';
 
 import { createClassName } from '../../../helpers/createClassName';
 import styles from './styles.scss';
 
-export const MessageBubble = memo(({ inverse, nude, quoted, className, style = {}, children, system = false }) => (
+type MessageBubbleProps = {
+	inverse?: boolean;
+	nude?: boolean;
+	quoted?: boolean;
+	className?: string;
+	style?: React.CSSProperties;
+	system?: boolean;
+	children?: ComponentChildren;
+};
+
+export const MessageBubble = memo(({ inverse, nude, quoted, className, style = {}, children, system = false }: MessageBubbleProps) => (
 	<div
 		data-qa='message-bubble'
 		className={createClassName(styles, 'message-bubble', { inverse, nude, quoted, system }, [className])}
diff --git a/packages/livechat/src/components/Messages/MessageContainer/index.js b/packages/livechat/src/components/Messages/MessageContainer/index.js
deleted file mode 100644
index 23a30ca556684a2a78de1898c0c52e6adf9c4aa1..0000000000000000000000000000000000000000
--- a/packages/livechat/src/components/Messages/MessageContainer/index.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import { memo } from 'preact/compat';
-
-import { createClassName } from '../../../helpers/createClassName';
-import styles from './styles.scss';
-
-export const MessageContainer = memo(({ id, compact, reverse, use: Element = 'div', className, style = {}, children, system = false }) => (
-	<Element id={id} className={createClassName(styles, 'message-container', { compact, reverse, system }, [className])} style={style}>
-		{children}
-	</Element>
-));
diff --git a/packages/livechat/src/components/Messages/MessageContainer/index.tsx b/packages/livechat/src/components/Messages/MessageContainer/index.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..62e49f61480aba8758571f7d2429f8c86fa1f650
--- /dev/null
+++ b/packages/livechat/src/components/Messages/MessageContainer/index.tsx
@@ -0,0 +1,26 @@
+import type { ComponentChildren } from 'preact';
+import { memo } from 'preact/compat';
+
+import { createClassName } from '../../../helpers/createClassName';
+import styles from './styles.scss';
+
+type MessageContainerProps = {
+	id?: string;
+	compact?: boolean;
+	reverse?: boolean;
+	use?: any;
+	className?: string;
+	style?: React.CSSProperties;
+	system?: boolean;
+	children?: ComponentChildren;
+};
+
+export const MessageContainer = memo(
+	// TODO: find a better way to pass `use` and do not default to a string
+	// eslint-disable-next-line @typescript-eslint/naming-convention
+	({ id, compact, reverse, use: Element = 'div', className, style = {}, children, system = false }: MessageContainerProps) => (
+		<Element id={id} className={createClassName(styles, 'message-container', { compact, reverse, system }, [className])} style={style}>
+			{children}
+		</Element>
+	),
+);
diff --git a/packages/livechat/src/components/Messages/MessageContent/index.js b/packages/livechat/src/components/Messages/MessageContent/index.tsx
similarity index 59%
rename from packages/livechat/src/components/Messages/MessageContent/index.js
rename to packages/livechat/src/components/Messages/MessageContent/index.tsx
index 251e942599b61d11289eea5d18fa6a3cbdb9fdaf..0cbad364e7d407ca0711bff34b1a14c4e6734615 100644
--- a/packages/livechat/src/components/Messages/MessageContent/index.js
+++ b/packages/livechat/src/components/Messages/MessageContent/index.tsx
@@ -1,9 +1,17 @@
+import type { ComponentChildren } from 'preact';
 import { memo } from 'preact/compat';
 
 import { createClassName } from '../../../helpers/createClassName';
 import styles from './styles.scss';
 
-export const MessageContent = memo(({ reverse, className, style = {}, children }) => (
+type MessageContentProps = {
+	reverse?: boolean;
+	className?: string;
+	style?: React.CSSProperties;
+	children?: ComponentChildren;
+};
+
+export const MessageContent = memo(({ reverse, className, style = {}, children }: MessageContentProps) => (
 	<div className={createClassName(styles, 'message-content', { reverse }, [className])} style={style}>
 		{children}
 	</div>
diff --git a/packages/livechat/src/components/Messages/MessageSeparator/index.js b/packages/livechat/src/components/Messages/MessageSeparator/index.tsx
similarity index 69%
rename from packages/livechat/src/components/Messages/MessageSeparator/index.js
rename to packages/livechat/src/components/Messages/MessageSeparator/index.tsx
index 0b19b50299034d1108640150cb6120f055136a6e..1cfdeb2fa93d16dadc00117fe83da3e2fa73a040 100644
--- a/packages/livechat/src/components/Messages/MessageSeparator/index.js
+++ b/packages/livechat/src/components/Messages/MessageSeparator/index.tsx
@@ -1,10 +1,23 @@
+import type { TFunction } from 'i18next';
+import type { CSSProperties } from 'preact/compat';
 import { memo } from 'preact/compat';
 import { withTranslation } from 'react-i18next';
 
 import { createClassName } from '../../../helpers/createClassName';
 import styles from './styles.scss';
 
-const MessageSeparator = ({ date, unread, use: Element = 'div', className, style = {}, t }) => (
+type MessageSeparatorProps = {
+	date?: string;
+	unread?: boolean;
+	className?: string;
+	style?: CSSProperties;
+	t: TFunction;
+	use?: any;
+};
+
+// TODO: find a better way to pass `use` and do not default to a string
+// eslint-disable-next-line @typescript-eslint/naming-convention
+const MessageSeparator = ({ date, unread, use: Element = 'div', className, style = {}, t }: MessageSeparatorProps) => (
 	<Element
 		className={createClassName(
 			styles,
diff --git a/packages/livechat/src/components/Messages/MessageTime/index.js b/packages/livechat/src/components/Messages/MessageTime/index.tsx
similarity index 53%
rename from packages/livechat/src/components/Messages/MessageTime/index.js
rename to packages/livechat/src/components/Messages/MessageTime/index.tsx
index 1c44695478bbfd0d92aaa678212a51f88e536884..b4a675e019f42dc335017ab9fe5a47048e48ef2c 100644
--- a/packages/livechat/src/components/Messages/MessageTime/index.js
+++ b/packages/livechat/src/components/Messages/MessageTime/index.tsx
@@ -1,12 +1,13 @@
 import { parseISO } from 'date-fns/fp';
 import isToday from 'date-fns/isToday';
+import type { TFunction } from 'i18next';
 import { memo } from 'preact/compat';
 import { withTranslation } from 'react-i18next';
 
 import { createClassName } from '../../../helpers/createClassName';
 import styles from './styles.scss';
 
-const parseDate = (ts, t) => {
+const parseDate = (ts: number, t: TFunction) => {
 	const timestamp = new Date(ts).toISOString();
 	return t('message_time', {
 		val: new Date(timestamp),
@@ -16,16 +17,26 @@ const parseDate = (ts, t) => {
 	});
 };
 
-const MessageTime = ({ ts, normal, inverted, className, style = {}, t }) => (
-	<div className={createClassName(styles, 'message-time-wrapper')}>
-		<time
-			dateTime={new Date(ts).toISOString()}
-			className={createClassName(styles, 'message-time', { normal, inverted }, [className])}
-			style={style}
-		>
-			{parseDate(ts, t)}
-		</time>
-	</div>
-);
+type MessageTimeProps = {
+	ts: number;
+	normal?: boolean;
+	inverted?: boolean;
+	className?: string;
+	style?: React.CSSProperties;
+	t: TFunction;
+};
+const MessageTime = ({ ts, normal, inverted, className, style = {}, t }: MessageTimeProps) => {
+	return (
+		<div className={createClassName(styles, 'message-time-wrapper')}>
+			<time
+				dateTime={new Date(ts).toISOString()}
+				className={createClassName(styles, 'message-time', { normal, inverted }, [className])}
+				style={style}
+			>
+				{parseDate(ts, t)}
+			</time>
+		</div>
+	);
+};
 
 export default withTranslation()(memo(MessageTime));
diff --git a/packages/livechat/src/components/Messages/TypingDots/index.js b/packages/livechat/src/components/Messages/TypingDots/index.tsx
similarity index 70%
rename from packages/livechat/src/components/Messages/TypingDots/index.js
rename to packages/livechat/src/components/Messages/TypingDots/index.tsx
index 3efa46a2403ceb9ce8d94d5d9469340a5f6e7588..79c2227a9afeda86598dfb55bae3aca982c53dc7 100644
--- a/packages/livechat/src/components/Messages/TypingDots/index.js
+++ b/packages/livechat/src/components/Messages/TypingDots/index.tsx
@@ -1,7 +1,13 @@
 import { createClassName } from '../../../helpers/createClassName';
 import styles from './styles.scss';
 
-export const TypingDots = ({ text, className, style = {} }) => (
+type TypingDotsProps = {
+	text: string;
+	className?: string;
+	style?: React.CSSProperties;
+};
+
+export const TypingDots = ({ text, className, style = {} }: TypingDotsProps) => (
 	<div aria-label={text} className={createClassName(styles, 'typing-dots', {}, [className])} style={style}>
 		<span class={createClassName(styles, 'typing-dots__dot')} />
 		<span class={createClassName(styles, 'typing-dots__dot')} />
diff --git a/packages/livechat/src/components/Messages/TypingIndicator/index.js b/packages/livechat/src/components/Messages/TypingIndicator/index.tsx
similarity index 67%
rename from packages/livechat/src/components/Messages/TypingIndicator/index.js
rename to packages/livechat/src/components/Messages/TypingIndicator/index.tsx
index 763caa1f247721afdfedb63ef363c02346f4fc3b..1018b2f7504e53bcd44b5c680b59c78c833f0f30 100644
--- a/packages/livechat/src/components/Messages/TypingIndicator/index.js
+++ b/packages/livechat/src/components/Messages/TypingIndicator/index.tsx
@@ -6,7 +6,13 @@ import { MessageContainer } from '../MessageContainer';
 import { MessageContent } from '../MessageContent';
 import { TypingDots } from '../TypingDots';
 
-export const TypingIndicator = memo(({ avatarResolver = () => null, usernames = [], text, ...containerProps }) => (
+type TypingIndicatorProps = {
+	avatarResolver: (username: string) => string | undefined;
+	usernames?: string[];
+	text: string;
+};
+
+export const TypingIndicator = memo(({ avatarResolver, usernames = [], text, ...containerProps }: TypingIndicatorProps) => (
 	<MessageContainer {...containerProps}>
 		<MessageAvatars avatarResolver={avatarResolver} usernames={usernames} />
 		<MessageContent>
diff --git a/packages/livechat/src/components/Messages/VideoAttachment/index.js b/packages/livechat/src/components/Messages/VideoAttachment/index.tsx
similarity index 80%
rename from packages/livechat/src/components/Messages/VideoAttachment/index.js
rename to packages/livechat/src/components/Messages/VideoAttachment/index.tsx
index 811a88255cbe5692a3ae7d5045ad36d65c094043..e0d72ad12915fb4df8cd90ca6c48e7875e485dcf 100644
--- a/packages/livechat/src/components/Messages/VideoAttachment/index.js
+++ b/packages/livechat/src/components/Messages/VideoAttachment/index.tsx
@@ -1,3 +1,4 @@
+import type { TFunction } from 'i18next';
 import { memo } from 'preact/compat';
 import { withTranslation } from 'react-i18next';
 
@@ -5,7 +6,12 @@ import { createClassName } from '../../../helpers/createClassName';
 import { MessageBubble } from '../MessageBubble';
 import styles from './styles.scss';
 
-const VideoAttachment = ({ url, className, t, ...messageBubbleProps }) => (
+type VideoAttachmentProps = {
+	url: string;
+	className?: string;
+	t: TFunction;
+};
+const VideoAttachment = ({ url, className, t, ...messageBubbleProps }: VideoAttachmentProps) => (
 	<MessageBubble nude className={createClassName(styles, 'video-attachment', {}, [className])} {...messageBubbleProps}>
 		<video src={url} controls className={createClassName(styles, 'video-attachment__inner')}>
 			{t('you_browser_doesn_t_support_video_element')}
diff --git a/packages/livechat/src/components/Messages/index.js b/packages/livechat/src/components/Messages/index.ts
similarity index 100%
rename from packages/livechat/src/components/Messages/index.js
rename to packages/livechat/src/components/Messages/index.ts