Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/clickable-option-type.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"dropzone": patch
---

Fix the declared type of `clickable` and `hiddenInputContainer`.

Both options are derived from their default values, so `clickable: true` was inferred as `boolean` and `hiddenInputContainer: "body"` as `string`. That contradicted what each one documents and what both have always accepted at runtime, and TypeScript rejected the documented forms.

`clickable` is now `boolean | string | HTMLElement | (string | HTMLElement)[]` and `hiddenInputContainer` is `string | HTMLElement`. Nothing changes at runtime.
2 changes: 1 addition & 1 deletion packages/dropzone/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
"build": "vite build && vite build --config vite.config.global.mjs && pnpm run css && pnpm run build:types",
"css": "lightningcss --minify --sourcemap --browserslist src/dropzone.css -o dist/dropzone.css && lightningcss --minify --sourcemap --browserslist src/basic.css -o dist/basic.css",
"build:types": "tsc",
"typecheck": "tsc --noEmit",
"typecheck": "tsc --noEmit -p tsconfig.typecheck.json",
"test": "vitest run",
"test:coverage": "vitest run --coverage",
"test:watch": "vitest",
Expand Down
4 changes: 2 additions & 2 deletions packages/dropzone/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ let defaultOptions = {
* or an array of those. In that case, all of those elements will trigger an
* upload when clicked.
*/
clickable: true,
clickable: true as boolean | string | HTMLElement | (string | HTMLElement)[],

/**
* Whether hidden files in directories should be ignored.
Expand Down Expand Up @@ -274,7 +274,7 @@ let defaultOptions = {
*
* Can be a selector string, or an element directly.
*/
hiddenInputContainer: "body",
hiddenInputContainer: "body" as string | HTMLElement,

/**
* If null, no capture type will be specified
Expand Down
44 changes: 44 additions & 0 deletions packages/dropzone/test/types/options.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Assertions about the option types, checked by `pnpm typecheck` and never
// emitted -- see tsconfig.typecheck.json.
//
// `DropzoneOptions` is derived from the default values, so an option is typed
// by whatever its default happens to be. Where a default is narrower than what
// the option accepts, the widening in options.ts is the only thing keeping the
// declaration honest, and nothing else would notice it being dropped. Hence
// these. A `@ts-expect-error` is itself an assertion: it fails the build if the
// line it marks stops being an error, so it also pins the type against being
// widened all the way to `any`.
import type { DropzoneOptions } from "../../src/options";

let element: HTMLElement = document.createElement("div");

// clickable: true for the dropzone element, false for nothing, or an element,
// a CSS selector, or an array of those. See #2373.
export const clickableTrue: DropzoneOptions = { clickable: true };
export const clickableFalse: DropzoneOptions = { clickable: false };
export const clickableElement: DropzoneOptions = { clickable: element };
export const clickableSelector: DropzoneOptions = { clickable: ".pick-files" };
export const clickableList: DropzoneOptions = { clickable: [element, ".pick-files"] };

// @ts-expect-error clickable is not a number
export const clickableNumber: DropzoneOptions = { clickable: 42 };

// hiddenInputContainer: a selector string or an element.
export const hiddenInputSelector: DropzoneOptions = { hiddenInputContainer: "body" };
export const hiddenInputElement: DropzoneOptions = { hiddenInputContainer: element };

// @ts-expect-error hiddenInputContainer is not a number
export const hiddenInputNumber: DropzoneOptions = { hiddenInputContainer: 42 };

// previewsContainer: a selector, an element, or false to opt out.
export const previewsSelector: DropzoneOptions = { previewsContainer: ".previews" };
export const previewsElement: DropzoneOptions = { previewsContainer: element };
export const previewsFalse: DropzoneOptions = { previewsContainer: false };

// @ts-expect-error previewsContainer is not a number
export const previewsNumber: DropzoneOptions = { previewsContainer: 42 };

// The lack of an index signature is deliberate: a misspelled option has to be
// an error rather than an unused custom key. See the note on DropzoneOptions.
// @ts-expect-error maxFileSize is the wrong capitalisation of maxFilesize
export const misspelled: DropzoneOptions = { maxFileSize: 4 };
13 changes: 13 additions & 0 deletions packages/dropzone/tsconfig.typecheck.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
// Type checking only, so it can reach files the build must not emit:
// test/types holds assertions about the public types, which would otherwise
// land in dist/ as declarations of their own.
"extends": "./tsconfig.json",
"compilerOptions": {
"noEmit": true,
"declaration": false,
"emitDeclarationOnly": false,
"rootDir": "."
},
"include": ["src/**/*.ts", "src/types.d.ts", "test/types/**/*.ts"]
}
Loading