Skip to content

[Bug] isCancel no longer narrows prompt results after 1.5.0 #600

Description

@dreyfus92

Environment

  • OS: macOS
  • Node Version: v24.20.0
  • Package: @clack/core, @clack/prompts
  • Package Version: core 1.5.0, prompts 1.8.0

Describe the bug

#592 changed isCancel from value is symbol to value is typeof CANCEL_SYMBOL, but every prompt still returns Promise<T | symbol> (core Prompt.prompt() and the 11 as Promise<... | symbol> casts in prompts). typescript can't subtract a unique symbol from symbol, so after the guard the result still has symbol in its type and any downstream use errors. this breaks code that type-checked fine on 1.7.0.

To Reproduce

import { path, isCancel } from '@clack/prompts';

const p = await path({ message: 'pick a file' });
if (isCancel(p)) process.exit(0);
console.log(`selected: ${p}`);
// TS2731: Implicit conversion of a 'symbol' to a 'string' will fail at runtime.

same snippet passes on prompts 1.7.0 / core 1.4.3. assigning the result to a string fails with TS2322 instead.

Expected behavior

isCancel narrows the cancel case away like it did before. #554 asked for the specific cancel type on prompt return types, and #592 only did the guard half, which is what left the two out of sync.

Activity

  1. 43081j commented on Sep 8, 2026

    @43081j
    Collaborator

    sad times.

    i blame the LLM that pushed us to make that change 😞 may just close them in future

    lets fix it in a patch. i think we can just update the prompts to return T | typeof CANCEL_SYMBOL

  2. gameroman commented on Sep 8, 2026

    @gameroman
    Member

    I wonder if we can just revert isCancel to value is symbol?

    export function isCancel(value: unknown): value is typeof CANCEL_SYMBOL {

    The reason they asked to export CANCEL_SYMBOL in the original issue was for tests but the other 2 points about "broad symbol type"

  3. 43081j commented on Sep 8, 2026

    @43081j
    Collaborator

    we can revert it but its technically more correct now than it was.

    i.e. a prompt currently can't return any symbol without breaking isCancel.

    so there's two options:

    1. go back, accept prompts that resolve to symbols can't use isCancel (what we had before)
    2. go forward, change every prompt to be | typeof CANCEL_SYMBOL instead of | symbol

    i'm happy to go with whatever you two think is the most sensible one. only really a select can produce a symbol today (select from a list of symbols), so its pretty low risk leaving it as it was (1)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions