Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Narrow handle function types based on "multiple" prop #139

Open
iGoodie opened this issue May 3, 2024 · 0 comments
Open

Narrow handle function types based on "multiple" prop #139

iGoodie opened this issue May 3, 2024 · 0 comments

Comments

@iGoodie
Copy link

iGoodie commented May 3, 2024

Hey! 👋🏼 Thanks a lot for implementing such a time-saver library!

When multiple prop is set to a falsy value, it is guaranteed to have exactly 1 file. However the typings on onDrop, onSelect and handleChange are widely typed to accommodate both cases. I'd expect them to be narrowed to accept File as their first argument when multiple is set to falsy value.


Current types:

<FileUploader
	onDrop={file => {}}
	// ^? (property) onDrop?: ((arg0: File | Array<File>) => void)
/>

<FileUploader
	multiple={false}
	onDrop={file => {}}
	// ^? (property) onDrop?: ((arg0: File | Array<File>) => void)
/>

<FileUploader
	multiple
	onDrop={files => {}}
	// ^? (property) onDrop?: ((arg0: File | Array<File>) => void)
/>

Expected narrowed types:

<FileUploader
	onDrop={file => {}}
	// ^? (property) onDrop?: ((file: File) => void)
/>

<FileUploader
	multiple={false}
	onDrop={file => {}}
	// ^? (property) onDrop?: ((file: File) => void)
/>

<FileUploader
	multiple
	onDrop={files => {}}
	// ^? (property) onDrop?: ((files: Array<File>) => void)
/>

This could be achieved by having Props implemented as a generic type. Theoretically with something like:

type FileFn<M extends boolean> = [boolean] extends [M]
  ? (arg: File | File[]) => void
  : M extends true
  ? (files: File[]) => void
  : (file: File) => void;

type Props<M extends boolean = false> = {
  multiple?: M;
  onDrop?: FileFn<M>;
  onSelect?: FileFn<M>;
  handleChange?: FileFn<M>;
  // ... other props are omitted
};

function FileUploader<M extends boolean = false>(props: Props<M>) {
  return <>{/* ... code is omitted. Returning props instead, to be able to test */}</>;
}

Tests:

type SingleTest = FileFn<false>;
//   ^? type SingleTest = (file: File) => void;

type MultiTest = FileFn<true>;
//   ^? type MultiTest = (files: File[]) => void

const dynamicValue = Math.random() >= 0.5;
<FileUploader multiple={dynamicValue} onDrop={} />;
//                                                               ^? (arg: File | File[]) => void

<FileUploader multiple handleChange={} />;
//                                   ^? (property) handleChange?: ((files: File[]) => void)

<FileUploader multiple={false} handleChange={} />;
//                                               ^? (property) handleChange?: ((file: File) => void)

<FileUploader handleChange={} />;
//                     ^? (property) handleChange?: ((file: File) => void)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant