简体   繁体   中英

Type asserting function in JSDoc

I am attempting to come up with a JavaScript+JSDoc variant of the following TypeScript type asserting function:

function typeCheck<T>(value: unknown, type: new () => T) {
    if (value instanceof type) {
        return value;
    }

    throw new Error('Invalid type');
}

const maybeButton: unknown = document.createElement('button');
const button = typeCheck(maybeButton, HTMLButtonElement);

I've come up with this but I'm getting an error:

/** @template T */
/** @returns {T} */
export default function check(/** @type {unknown} */ object, /** @type {new () => T} */ type) {
  if (object instanceof type) {
    /** @type {any} */
    const any = object;

    /** @type {T} */
    const t = any;

    return t;
  }

  throw new Error(`Object ${object} does not have the right type '${type}'!`)
}

The error is in the call site: const button = check(event.currentTarget, HTMLButtonElement); . HTMLButtonElement is underlined and the error message says:

Argument of type '{ new (): HTMLButtonElement; prototype: HTMLButtonElement; }' is not assignable to parameter of type 'new () => T'.
  Type 'HTMLButtonElement' is not assignable to type 'T'.
    'T' could be instantiated with an arbitrary type which could be unrelated to 'HTMLButtonElement'.ts(2345)

Is it possible to develop a JSDoc function like this which when passed an unknown would solely using TypeScript type interference and escape analysis validate and return the unknown object typed as the provided type?

I am not interested in JSDoc in general, but specifically JSDoc as used in Visual Studio Code with the TypeScript language service working on a JavaScript project using JSDoc for type hints.

Assertion Functions introduced in TS 3.7 can assert the type of a value in their calling scope.

/**
 * @param {*} maybeString
 * @returns {asserts maybeString is string}
 */
function assertString(maybeString) {
  if (typeof maybeString !== 'string') throw Error('not a string');
}

/**
 * @param {unknown} something
 */
function demo(something) {
  something.concat; // type error
  assertString(something);
  something.concat; // valid
}

Someone on the TypeScript Discord helped me come up with the answer:

/**
 * @template T
 * @returns {T}
 * @param {unknown} obj
 * @param {new () => T} type
 */
export default function assertInstance(obj, type) {
  if (obj instanceof type) {
    /** @type {any} */
    const any = obj;

    /** @type {T} */
    const t = any;

    return t;
  }

  throw new Error(`Object ${obj} does not have the right type '${type}'!`)
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM