Typescript: Type guard annotations don't work in jsdoc

Created on 21 Jun 2018  路  5Comments  路  Source: microsoft/TypeScript

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.

JSDoc Fixed Suggestion

Most helpful comment

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";
}

All 5 comments

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'.

Based on the above, you should write:

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

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
}

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

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";
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

uber5001 picture uber5001  路  3Comments

Roam-Cooper picture Roam-Cooper  路  3Comments

Antony-Jones picture Antony-Jones  路  3Comments

weswigham picture weswigham  路  3Comments

CyrusNajmabadi picture CyrusNajmabadi  路  3Comments