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

TS2416 with typescript 5.6 when using disposable lib #60145

Closed
jameslan opened this issue Oct 5, 2024 · 3 comments
Closed

TS2416 with typescript 5.6 when using disposable lib #60145

jameslan opened this issue Oct 5, 2024 · 3 comments
Assignees
Labels
External Relates to another program, environment, or user action which we cannot control.

Comments

@jameslan
Copy link
Contributor

jameslan commented Oct 5, 2024

πŸ”Ž Search Terms

disposable ts2416

πŸ•— Version & Regression Information

⏯ Playground Link

No response

πŸ’» Code

I am writing a typedoc plugin and needs to import typedoc, in its dist/lib/utils/map.d.ts(https://www.npmjs.com/package/typedoc?activeTab=code), it has the following declaration,

export declare class StableKeyMap<K extends {
    getStableKey(): string;
}, V> implements Map<K, V> {
    [Symbol.toStringTag]: string;
    private impl;
    get size(): number;
    set(key: K, value: V): this;
    get(key: K): V | undefined;
    has(key: K): boolean;
    clear(): void;
    delete(key: K): boolean;
    forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void, thisArg?: any): void;
    entries(): IterableIterator<[K, V]>;
    keys(): IterableIterator<K>;
    values(): IterableIterator<V>;
    [Symbol.iterator](): IterableIterator<[K, V]>;
}

πŸ™ Actual behavior

There are several errors complaining incompatibility between IterableIterator and MapIterator, one of them is like,

node_modules/typedoc/dist/lib/utils/map.d.ts:19:5 - error TS2416: Property 'entries' in type 'StableKeyMap<K, V>' is not assignable to the same property in base type 'Map<K, V>'.
  Type '() => IterableIterator<[K, V]>' is not assignable to type '() => MapIterator<[K, V]>'.
    Property '[Symbol.dispose]' is missing in type 'IterableIterator<[K, V]>' but required in type 'MapIterator<[K, V]>'.

19     entries(): IterableIterator<[K, V]>;
       ~~~~~~~

  node_modules/typescript/lib/lib.esnext.disposable.d.ts:36:5
    36     [Symbol.dispose](): void;
           ~~~~~~~~~~~~~~~~~~~~~~~~~
    '[Symbol.dispose]' is declared here.

πŸ™‚ Expected behavior

typescript 5.5 and 5.4 pass transpilation smoothly.

Additional information about the issue

In the tsconfig.json, I enabled disposable lib otherwise it will complain about Symbol.disposable:

"lib": ["es2015", "dom", "esnext.disposable"],
@RyanCavanaugh RyanCavanaugh added the Needs Investigation This issue needs a team member to investigate its status. label Oct 8, 2024
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 5.7.0 milestone Oct 8, 2024
@rbuckton
Copy link
Member

rbuckton commented Oct 17, 2024

It's generally a bad idea to use implements Map in user code unless you are writing a polyfill for Map. As evidenced by the recent additions to Set (https://github.com/tc39/proposal-set-methods) and the upcoming additions to Map (https://github.com/tc39/proposal-upsert), as well as the changes to built-in iterators (https://github.com/tc39/proposal-iterator-helpers), these types can change as ECMAScript evolves.

As we must update the lib types to support the evolution of the language, we must sometimes break compatibility from version to version. We have, on occasion, made features available in the language to assist with transitional changes from version to version, such as typesVersions, though typesVersions is a fairly manual process intended for library authors to ship alternate declarations for earlier versions of TypeScript.

In the case of typedoc, they may need to either use typesVersions or update their types to use a compatible return type, such as:

export declare class StableKeyMap<K extends {
    getStableKey(): string;
}, V> implements Map<K, V> {
    [Symbol.toStringTag]: string;
    private impl;
    get size(): number;
    set(key: K, value: V): this;
    get(key: K): V | undefined;
    has(key: K): boolean;
    clear(): void;
    delete(key: K): boolean;
    forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void, thisArg?: any): void;
    entries(): ReturnType<Map<K, V>["entries"]>;
    keys(): ReturnType<Map<K, V>["keys"]>;
    values(): ReturnType<Map<K, V>["values"]>;
    [Symbol.iterator](): ReturnType<Map<K, V>[typeof Symbol.iterator]>;
}

In the meantime, you should be able to work around this issue by using "skipLibChecks": true in your tsconfig.json file.

@rbuckton
Copy link
Member

You can also work around this by adding a module augmentation to your code that introduces overloads that make the type compatible:

declare module "typedoc/dist/lib/utils/map" {
    interface StableKeyMap<K extends { getStableKey(): string; }, V> {
        entries(): MapIterator<[K, V]>;
        keys(): MapIterator<K>;
        values(): MapIterator<V>;
        [Symbol.iterator](): MapIterator<[K, V]>;
    }
}

Take care, however, that these methods in StableKeyMap actually produce an iterator that has the appropriate Iterator helper methods and [Symbol.dispose](), or that you refrain from using these methods in your code.

@rbuckton rbuckton added External Relates to another program, environment, or user action which we cannot control. and removed Needs Investigation This issue needs a team member to investigate its status. labels Oct 17, 2024
@rbuckton
Copy link
Member

It looks like this is being tracked by TypeStrong/typedoc#2747.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
External Relates to another program, environment, or user action which we cannot control.
Projects
None yet
Development

No branches or pull requests

3 participants