feat(prompts): add onCancel callback option to all prompts#544
Conversation
🦋 Changeset detectedLatest commit: 5a5d7ac The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Unsafely, yes: const result = await confirm({
message: "Continue?",
onCancel: () => {
console.log("do anything here that _doesn't_ process.exit");
},
});
// result is still T | Symbol at runtimei'm not sure we should go down this path yet until the issue has a resolution. my main concern is that this is mixing two different architectures:
we currently use the first one. introducing the second means we now have two ways of dealing with cancellations, which seems awkward to me. ultimately you're just trying to avoid having to type-check results, but that takes about as much code as your |
Add optional onCancel callback to CommonOptions, available on all 12 prompts. When the callback returns `never` (e.g. calls process.exit or throws), the prompt's return type narrows to exclude the cancel symbol via function overloads. - Add handleCancel utility in common.ts - Add function overloads with () => never for type-safe narrowing - Convert prompts from const arrows to function declarations (required for overloads) - Comprehensive runtime tests for all 12 prompts - Update README and changeset
|
@43081j Thanks for the feedback! You were right that the previous version was unsound. I've updated the PR to address your concerns. Type narrowing is now sound using export function confirm(opts: ConfirmOptions & { onCancel: () => never }): Promise<boolean>;
export function confirm(opts: ConfirmOptions): Promise<boolean | symbol>;Narrowing only triggers when the callback's return type is Symbols remain the single source of truth. The gain isn't about saving lines — it's about the compiler enforcing that cancellation is handled. With |
Summary
Adds an optional
onCancelcallback to all prompt functions viaCommonOptions. When the user cancels a prompt (Ctrl+C or Escape), the callback is invoked — eliminating the need forisCancelguards at every call site. WhenonCancelis provided, the return type narrows fromPromise<T | symbol>toPromise<T>.Closes #83
Motivation
Every clack user repeats this pattern:
This PR makes it:
Changes
CommonOptions— addedonCancel?: () => voidhandleCancelutility — exported from@clack/promptsfor custom prompt implementationsType narrowing
Each prompt uses function overloads so TypeScript narrows the return type when
onCancelis present:This works for all prompts:
text,confirm,select,multiselect,groupMultiselect,password,autocomplete,autocompleteMultiselect,selectKey,date,multiline,path.Design decisions
onCancelis optional; existing code works unchangedexport constarrows toexport functiondeclarationshandleCancelis exported — useful for custom prompt implementationsTest plan
pnpm run buildsucceedspnpm run typessucceedspnpm run lintsucceedspnpm run formatsucceeds@ts-expect-error)