Skip to main content
Back to contributions
Pull Request
Open
26.5K

Make FileUploadModalData.attachments optional

discordjs/discord.js

Fixed TypeScript typings to correctly mark modal attachments as optional when users don't upload files

The Problem

When building Discord bots with discord.js, developers can create modals with optional FileUpload components that allow users to attach files. However, a type safety gap existed between TypeScript’s compile-time checks and the actual runtime behavior.

The TypeScript type definitions marked the attachments field as required in the FileUploadModalData interface. In reality, when a user submits a modal without uploading any files, component.attachments is undefined at runtime. This mismatch meant developers could write code that TypeScript considered perfectly valid, only to have it crash in production.

Consider this seemingly safe code pattern:

for (const field of ctx.fields.components.filter((c) => c.type === ComponentType.Label)) {
  const comp = field.component;
  if (comp.type === ComponentType.FileUpload) {
    // TypeScript says this is fine, but it throws at runtime!
    const fieldAttachments = comp.attachments.values().toArray();
  }
}

Calling comp.attachments.values() without a null check throws TypeError: undefined is not an object when the user doesn’t upload a file. Developers had to discover this the hard way and manually add optional chaining (comp.attachments?.values()) as a workaround.

The Solution

The fix was straightforward: update the type definition to accurately reflect the runtime behavior by making the attachments property optional.

// Before - incorrectly marked as required
attachments: ReadonlyCollection<Snowflake, Attachment>;

// After - correctly marked as optional
attachments?: ReadonlyCollection<Snowflake, Attachment>;

This single-character change (?) enables TypeScript to catch unsafe access patterns during compilation. Developers now get proper IDE warnings and compile-time errors when accessing attachments without first checking if it exists.

Files Changed

FileChanges
packages/discord.js/typings/index.d.ts+1 −1

Review Discussion

During the review process, maintainer vladfrangu raised an interesting architectural question: “Is there a reason we don’t just always create a collection?” Team member Jiralite suggested that if the API receives an empty array, it should create an empty collection instead of undefined. This indicates potential future improvements to the discord.js codebase that could eliminate this edge case entirely.

Timeline

DateEvent
2025-12-13Issue #11359 reported by The-LukeZ
2025-12-13Forked repo, implemented fix, submitted PR #11363
2025-12-17Received first approval from almeidx
2025-12-18All CI checks passing
2026-01-02Additional review discussion from maintainers

Impact

This fix improves type safety for all discord.js developers working with modal file uploads (v14.25.1+). By aligning TypeScript types with actual runtime behavior, it helps catch bugs at compile time rather than in production, following TypeScript’s core philosophy of providing strong type guarantees.