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

Type guard annotations don't work in jsdoc #25127

Closed
sandersn opened this issue Jun 21, 2018 · 5 comments
Closed

Type guard annotations don't work in jsdoc #25127

sandersn opened this issue Jun 21, 2018 · 5 comments
Labels
Domain: JSDoc Relates to JSDoc parsing and type generation Fixed A PR has been merged for this issue Suggestion An idea for TypeScript

Comments

@sandersn
Copy link
Member

class Entry {
    constructor() {
        this.c = 1
    }
    /**
     * @param {any} x
     * @return {this is Entry}
     */
    isInit(x) {
        return true
    }
}
class Group {
    constructor() {
        this.d = 'no'
    }
    /**
     * @param {any} x
     * @return {false}
     */
    isInit(x) {
        return false
    }
}
/** @param {Entry | Group} chunk */
function f(chunk) {
    let x = chunk.isInit(chunk) ? chunk.c : chunk.d
    return x
}

Expected behavior:
Should be equivalent to

declare class C {
    c: number
    isInit(x: any): this is C
}
declare class D {
    d: string
    isInit(x: any): false
}
function f (g: C | D) {
    let x = g.isInit(g) ? g.c : g.d
}

And narrow upon calling isInit.

Actual behavior:

No narrowing, and Entry.isInit's return type is just boolean.

@spiffytech
Copy link

On TypeScript 3.0rc I cannot guard function parameters:

/**
 * @param {any} options
 * @return {options is MyOptions}
 */
function isMyOptions(options) {
  return true;
}

Cannot find name 'options'.

@kitsonk
Copy link
Contributor

kitsonk commented Jul 14, 2018

Based on the above, you should write:

-  * @return {options is MyOptions}
+  * @return {this is MyOptions}

@spiffytech
Copy link

Assert this even though I'm not typing a class like the OP, but a function parameter? I've attempted what you suggested, but JSDoc TypeScript does not change the options value from its original type after checking it with the guard, as happens in ordinary TypeScript files.

/**
 * @param {RequestOptions} options
 * @return {this is MyOptions}
 */
function isMyOptions(options) {
  return true  // would normally check options.type
}

/**
 * @param {MyOptions} options
 */
function takesMyOptions(options) {
  console.log(options.specialField);
}

/**
 * @param {Request<RequestOptions>} request
 */
function doWork(request) {
  const options = request.options;  // type RequestOptions
  if (!isMyOptions(options)) throw new Error('Request was not of type MyOptions');
  takesMyOptions(options);  // Still type RequestOptions, TypeScript error
}

@connorjclark
Copy link
Contributor

@spiffytech try using any for the type of options in isMyOptions, and replace the this with options in the return type.

@sirlancelot
Copy link
Contributor

For anyone Googling, this has been fixed by #26297. Use the name of the argument in the is clause (not this). Here is the correct syntax:

// @ts-check
/**
 * @param {any} value
 * @return {value is boolean}
 */
function isBoolean(value) {
	return typeof value === "boolean";
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Domain: JSDoc Relates to JSDoc parsing and type generation Fixed A PR has been merged for this issue Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

7 participants