Skip to content

lib.dom.ts LockManager Incorrect #62231

@tustvold

Description

@tustvold

🔎 Search Terms

Prior to version 5.9.0 the definition for LockManager was

interface LockManager {
    /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/LockManager/query) */
    query(): Promise<LockManagerSnapshot>;
    /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/LockManager/request) */
    request(name: string, callback: LockGrantedCallback): Promise<any>;
    request(name: string, options: LockOptions, callback: LockGrantedCallback): Promise<any>;
}

In 5.9 this was changed to

interface LockManager {
    /**
     * The **`query()`** method of the LockManager interface returns a Promise that resolves with an object containing information about held and pending locks.
     *
     * [MDN Reference](https://developer.mozilla.org/docs/Web/API/LockManager/query)
     */
    query(): Promise<LockManagerSnapshot>;
    /**
     * The **`request()`** method of the LockManager interface requests a Lock object with parameters specifying its name and characteristics.
     *
     * [MDN Reference](https://developer.mozilla.org/docs/Web/API/LockManager/request)
     */
    request<T>(name: string, callback: LockGrantedCallback<T>): Promise<T>;
    request<T>(name: string, options: LockOptions, callback: LockGrantedCallback<T>): Promise<T>;
}

interface LockGrantedCallback<T> {
    (lock: Lock | null): T;
}

The result is that calling LockManager with an async closure, as described in the w3c fails to type check correctly - as it infers the type of T to be a Promise and therefore the result of calling request to be Promise<Promise<T>> which is incorrect.

The return type of LockGrantedCallback is not necessarily wrong, a method can return T and navigator will wrap it a promise that resolves in an upcoming microtask, however, the signature returning Promise<T> is also valid and should not alter the return type of request.

🕗 Version & Regression Information

This changed between versions 5.8.3 and 5.9.2

⏯ Playground Link

No response

💻 Code

function criticalSection<T>(name: string, func: () => Promise<T>): Promise<T> {
  if (navigator.locks?.request) {
    return navigator.locks.request(name, func);
  }
  console.log("No lock provider - likely not a secure context");
  return func();
}

🙁 Actual behavior

function criticalSection<T>(name: string, func: () => Promise<T>): Promise<T> {
  if (navigator.locks?.request) {
    return navigator.locks.request(name, func);
  }
  console.log("No lock provider - likely not a secure context");
  return func();
}

Returns the error

error TS2322: Type 'Promise<Promise<T>>' is not assignable to type 'Promise<T>'.
  Type 'Promise<T>' is not assignable to type 'T'.
    'T' could be instantiated with an arbitrary type which could be unrelated to 'Promise<T>'.

<REDACTED>     return navigator.locks.request(name, func);

🙂 Expected behavior

It should typecheck

Additional information about the issue

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugA bug in TypeScriptDomain: lib.d.tsThe issue relates to the different libraries shipped with TypeScript

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions