V2 Make FileId type opaque and use consistently throughout project (#4307)

# Description of Changes
The `FileId` type in V2 currently is just defined to be a string. This
makes it really easy to accidentally pass strings into things accepting
file IDs (such as file names). This PR makes the `FileId` type [an
opaque
type](https://www.geeksforgeeks.org/typescript/opaque-types-in-typescript/),
so it is compatible with things accepting strings (arguably not ideal
for this...) but strings are not compatible with it without explicit
conversion.

The PR also includes changes to use `FileId` consistently throughout the
project (everywhere I could find uses of `fileId: string`), so that we
have the maximum benefit from the type safety.

> [!note]
> I've marked quite a few things as `FIX ME` where we're passing names
in as IDs. If that is intended behaviour, I'm happy to remove the fix me
and insert a cast instead, but they probably need comments explaining
why we're using a file name as an ID.
This commit is contained in:
James Brunton
2025-08-28 09:56:07 +00:00
committed by GitHub
parent 581bafbd37
commit e142af2863
32 changed files with 600 additions and 574 deletions
@@ -11,9 +11,10 @@ import { draggable, dropTargetForElements } from '@atlaskit/pragmatic-drag-and-d
import styles from './FileEditor.module.css';
import { useFileContext } from '../../contexts/FileContext';
import { FileId } from '../../types/file';
interface FileItem {
id: string;
id: FileId;
name: string;
pageCount: number;
thumbnail: string | null;
@@ -25,14 +26,14 @@ interface FileEditorThumbnailProps {
file: FileItem;
index: number;
totalFiles: number;
selectedFiles: string[];
selectedFiles: FileId[];
selectionMode: boolean;
onToggleFile: (fileId: string) => void;
onDeleteFile: (fileId: string) => void;
onViewFile: (fileId: string) => void;
onToggleFile: (fileId: FileId) => void;
onDeleteFile: (fileId: FileId) => void;
onViewFile: (fileId: FileId) => void;
onSetStatus: (status: string) => void;
onReorderFiles?: (sourceFileId: string, targetFileId: string, selectedFileIds: string[]) => void;
onDownloadFile?: (fileId: string) => void;
onReorderFiles?: (sourceFileId: FileId, targetFileId: FileId, selectedFileIds: FileId[]) => void;
onDownloadFile?: (fileId: FileId) => void;
toolMode?: boolean;
isSupported?: boolean;
}
@@ -161,8 +162,8 @@ const FileEditorThumbnail = ({
onDrop: ({ source }) => {
const sourceData = source.data;
if (sourceData.type === 'file' && onReorderFiles) {
const sourceFileId = sourceData.fileId as string;
const selectedFileIds = sourceData.selectedFiles as string[];
const sourceFileId = sourceData.fileId as FileId;
const selectedFileIds = sourceData.selectedFiles as FileId[];
onReorderFiles(sourceFileId, file.id, selectedFileIds);
}
}
@@ -332,7 +333,7 @@ const FileEditorThumbnail = ({
)}
{/* Title + meta line */}
<div
<div
style={{
padding: '0.5rem',
textAlign: 'center',
@@ -404,4 +405,4 @@ const FileEditorThumbnail = ({
);
};
export default React.memo(FileEditorThumbnail);
export default React.memo(FileEditorThumbnail);