Skip to content

Type definitions for 'Symbols as WeakMap keys' (#76) #54195

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

Merged
merged 3 commits into from
Jun 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/compiler/commandLineParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,9 @@ const libEntries: [string, string][] = [
["es2022.string", "lib.es2022.string.d.ts"],
["es2022.regexp", "lib.es2022.regexp.d.ts"],
["es2023.array", "lib.es2023.array.d.ts"],
["es2023.collection", "lib.es2023.collection.d.ts"],
["esnext.array", "lib.es2023.array.d.ts"],
["esnext.collection", "lib.es2023.collection.d.ts"],
["esnext.symbol", "lib.es2019.symbol.d.ts"],
["esnext.asynciterable", "lib.es2018.asynciterable.d.ts"],
["esnext.intl", "lib.esnext.intl.d.ts"],
Expand Down
2 changes: 2 additions & 0 deletions src/harness/fourslashInterfaceImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1225,6 +1225,8 @@ export namespace Completion {
varEntry("Float64Array"),
interfaceEntry("Float64ArrayConstructor"),
moduleEntry("Intl"),
typeEntry("WeakKey"),
interfaceEntry("WeakKeyTypes"),
];

export const globalThisEntry: ExpectedCompletionEntry = {
Expand Down
18 changes: 9 additions & 9 deletions src/lib/es2015.collection.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ interface ReadonlyMap<K, V> {
readonly size: number;
}

interface WeakMap<K extends object, V> {
interface WeakMap<K extends WeakKey, V> {
/**
* Removes the specified element from the WeakMap.
* @returns true if the element was successfully removed, or false if it was not present.
Expand All @@ -58,14 +58,14 @@ interface WeakMap<K extends object, V> {
has(key: K): boolean;
/**
* Adds a new element with a specified key and value.
* @param key Must be an object.
* @param key Must be an object or symbol.
*/
set(key: K, value: V): this;
}

interface WeakMapConstructor {
new <K extends object = object, V = any>(entries?: readonly (readonly [K, V])[] | null): WeakMap<K, V>;
readonly prototype: WeakMap<object, any>;
new <K extends WeakKey = WeakKey, V = any>(entries?: readonly [K, V][] | null): WeakMap<K, V>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regression from #50449.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, thanks for catching this. I missed it in the review.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#54592 will fix this

readonly prototype: WeakMap<WeakKey, any>;
}
declare var WeakMap: WeakMapConstructor;

Expand Down Expand Up @@ -107,9 +107,9 @@ interface ReadonlySet<T> {
readonly size: number;
}

interface WeakSet<T extends object> {
interface WeakSet<T extends WeakKey> {
/**
* Appends a new object to the end of the WeakSet.
* Appends a new value to the end of the WeakSet.
*/
add(value: T): this;
/**
Expand All @@ -118,13 +118,13 @@ interface WeakSet<T extends object> {
*/
delete(value: T): boolean;
/**
* @returns a boolean indicating whether an object exists in the WeakSet or not.
* @returns a boolean indicating whether a value exists in the WeakSet or not.
*/
has(value: T): boolean;
}

interface WeakSetConstructor {
new <T extends object = object>(values?: readonly T[] | null): WeakSet<T>;
readonly prototype: WeakSet<object>;
new <T extends WeakKey = WeakKey>(values?: readonly T[] | null): WeakSet<T>;
readonly prototype: WeakSet<WeakKey>;
}
declare var WeakSet: WeakSetConstructor;
8 changes: 4 additions & 4 deletions src/lib/es2015.iterable.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,10 @@ interface MapConstructor {
new <K, V>(iterable?: Iterable<readonly [K, V]> | null): Map<K, V>;
}

interface WeakMap<K extends object, V> { }
interface WeakMap<K extends WeakKey, V> { }

interface WeakMapConstructor {
new <K extends object, V>(iterable: Iterable<readonly [K, V]>): WeakMap<K, V>;
new <K extends WeakKey, V>(iterable: Iterable<readonly [K, V]>): WeakMap<K, V>;
}

interface Set<T> {
Expand Down Expand Up @@ -189,10 +189,10 @@ interface SetConstructor {
new <T>(iterable?: Iterable<T> | null): Set<T>;
}

interface WeakSet<T extends object> { }
interface WeakSet<T extends WeakKey> { }

interface WeakSetConstructor {
new <T extends object = object>(iterable: Iterable<T>): WeakSet<T>;
new <T extends WeakKey = WeakKey>(iterable: Iterable<T>): WeakSet<T>;
}

interface Promise<T> { }
Expand Down
4 changes: 2 additions & 2 deletions src/lib/es2015.symbol.wellknown.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,15 +119,15 @@ interface Map<K, V> {
readonly [Symbol.toStringTag]: string;
}

interface WeakMap<K extends object, V> {
interface WeakMap<K extends WeakKey, V> {
readonly [Symbol.toStringTag]: string;
}

interface Set<T> {
readonly [Symbol.toStringTag]: string;
}

interface WeakSet<T extends object> {
interface WeakSet<T extends WeakKey> {
readonly [Symbol.toStringTag]: string;
}

Expand Down
35 changes: 19 additions & 16 deletions src/lib/es2021.weakref.d.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
interface WeakRef<T extends object> {
interface WeakRef<T extends WeakKey> {
readonly [Symbol.toStringTag]: "WeakRef";

/**
* Returns the WeakRef instance's target object, or undefined if the target object has been
* Returns the WeakRef instance's target value, or undefined if the target value has been
* reclaimed.
* In es2023 the value can be either a symbol or an object, in previous versions only object is permissible.
*/
deref(): T | undefined;
}
Expand All @@ -12,10 +13,11 @@ interface WeakRefConstructor {
readonly prototype: WeakRef<any>;

/**
* Creates a WeakRef instance for the given target object.
* @param target The target object for the WeakRef instance.
* Creates a WeakRef instance for the given target value.
* In es2023 the value can be either a symbol or an object, in previous versions only object is permissible.
* @param target The target value for the WeakRef instance.
*/
new<T extends object>(target: T): WeakRef<T>;
new<T extends WeakKey>(target: T): WeakRef<T>;
}

declare var WeakRef: WeakRefConstructor;
Expand All @@ -24,30 +26,31 @@ interface FinalizationRegistry<T> {
readonly [Symbol.toStringTag]: "FinalizationRegistry";

/**
* Registers an object with the registry.
* @param target The target object to register.
* @param heldValue The value to pass to the finalizer for this object. This cannot be the
* target object.
* Registers a value with the registry.
* In es2023 the value can be either a symbol or an object, in previous versions only object is permissible.
* @param target The target value to register.
* @param heldValue The value to pass to the finalizer for this value. This cannot be the
* target value.
* @param unregisterToken The token to pass to the unregister method to unregister the target
* object. If provided (and not undefined), this must be an object. If not provided, the target
* cannot be unregistered.
* value. If not provided, the target cannot be unregistered.
*/
register(target: object, heldValue: T, unregisterToken?: object): void;
register(target: WeakKey, heldValue: T, unregisterToken?: WeakKey): void;

/**
* Unregisters an object from the registry.
* Unregisters a value from the registry.
* In es2023 the value can be either a symbol or an object, in previous versions only object is permissible.
* @param unregisterToken The token that was used as the unregisterToken argument when calling
* register to register the target object.
* register to register the target value.
*/
unregister(unregisterToken: object): void;
unregister(unregisterToken: WeakKey): void;
}

interface FinalizationRegistryConstructor {
readonly prototype: FinalizationRegistry<any>;

/**
* Creates a finalization registry with an associated cleanup callback
* @param cleanupCallback The callback to call after an object in the registry has been reclaimed.
* @param cleanupCallback The callback to call after a value in the registry has been reclaimed.
*/
new<T>(cleanupCallback: (heldValue: T) => void): FinalizationRegistry<T>;
}
Expand Down
3 changes: 3 additions & 0 deletions src/lib/es2023.collection.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
interface WeakKeyTypes {
symbol: symbol;
}
1 change: 1 addition & 0 deletions src/lib/es2023.d.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/// <reference lib="es2022" />
/// <reference lib="es2023.array" />
/// <reference lib="es2023.collection" />
9 changes: 9 additions & 0 deletions src/lib/es5.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1647,6 +1647,15 @@ type Uncapitalize<S extends string> = intrinsic;
*/
interface ThisType<T> { }

/**
* Stores types to be used with WeakSet, WeakMap, WeakRef, and FinalizationRegistry
*/
interface WeakKeyTypes {
object: object;
}

type WeakKey = WeakKeyTypes[keyof WeakKeyTypes];

/**
* Represents a raw buffer of binary data, which is used to store data for the
* different typed arrays. ArrayBuffers cannot be read from or written to directly,
Expand Down
1 change: 1 addition & 0 deletions src/lib/libs.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"es2022.string",
"es2022.regexp",
"es2023.array",
"es2023.collection",
"esnext.intl",
"decorators",
"decorators.legacy",
Expand Down
40 changes: 40 additions & 0 deletions tests/baselines/reference/acceptSymbolAsWeakType.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//// [tests/cases/compiler/acceptSymbolAsWeakType.ts] ////

//// [acceptSymbolAsWeakType.ts]
const s: symbol = Symbol('s');

const ws = new WeakSet([s]);
ws.add(s);
ws.has(s);
ws.delete(s);

const wm = new WeakMap([[s, false]]);
wm.set(s, true);
wm.has(s);
wm.get(s);
wm.delete(s);

const wr = new WeakRef(s);
wr.deref();

const f = new FinalizationRegistry(() => {});
f.register(s, null);
f.unregister(s);

//// [acceptSymbolAsWeakType.js]
"use strict";
const s = Symbol('s');
const ws = new WeakSet([s]);
ws.add(s);
ws.has(s);
ws.delete(s);
const wm = new WeakMap([[s, false]]);
wm.set(s, true);
wm.has(s);
wm.get(s);
wm.delete(s);
const wr = new WeakRef(s);
wr.deref();
const f = new FinalizationRegistry(() => { });
f.register(s, null);
f.unregister(s);
85 changes: 85 additions & 0 deletions tests/baselines/reference/acceptSymbolAsWeakType.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//// [tests/cases/compiler/acceptSymbolAsWeakType.ts] ////

=== acceptSymbolAsWeakType.ts ===
const s: symbol = Symbol('s');
>s : Symbol(s, Decl(acceptSymbolAsWeakType.ts, 0, 5))
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --))

const ws = new WeakSet([s]);
>ws : Symbol(ws, Decl(acceptSymbolAsWeakType.ts, 2, 5))
>WeakSet : Symbol(WeakSet, Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
>s : Symbol(s, Decl(acceptSymbolAsWeakType.ts, 0, 5))

ws.add(s);
>ws.add : Symbol(WeakSet.add, Decl(lib.es2015.collection.d.ts, --, --))
>ws : Symbol(ws, Decl(acceptSymbolAsWeakType.ts, 2, 5))
>add : Symbol(WeakSet.add, Decl(lib.es2015.collection.d.ts, --, --))
>s : Symbol(s, Decl(acceptSymbolAsWeakType.ts, 0, 5))

ws.has(s);
>ws.has : Symbol(WeakSet.has, Decl(lib.es2015.collection.d.ts, --, --))
>ws : Symbol(ws, Decl(acceptSymbolAsWeakType.ts, 2, 5))
>has : Symbol(WeakSet.has, Decl(lib.es2015.collection.d.ts, --, --))
>s : Symbol(s, Decl(acceptSymbolAsWeakType.ts, 0, 5))

ws.delete(s);
>ws.delete : Symbol(WeakSet.delete, Decl(lib.es2015.collection.d.ts, --, --))
>ws : Symbol(ws, Decl(acceptSymbolAsWeakType.ts, 2, 5))
>delete : Symbol(WeakSet.delete, Decl(lib.es2015.collection.d.ts, --, --))
>s : Symbol(s, Decl(acceptSymbolAsWeakType.ts, 0, 5))

const wm = new WeakMap([[s, false]]);
>wm : Symbol(wm, Decl(acceptSymbolAsWeakType.ts, 7, 5))
>WeakMap : Symbol(WeakMap, Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
>s : Symbol(s, Decl(acceptSymbolAsWeakType.ts, 0, 5))

wm.set(s, true);
>wm.set : Symbol(WeakMap.set, Decl(lib.es2015.collection.d.ts, --, --))
>wm : Symbol(wm, Decl(acceptSymbolAsWeakType.ts, 7, 5))
>set : Symbol(WeakMap.set, Decl(lib.es2015.collection.d.ts, --, --))
>s : Symbol(s, Decl(acceptSymbolAsWeakType.ts, 0, 5))

wm.has(s);
>wm.has : Symbol(WeakMap.has, Decl(lib.es2015.collection.d.ts, --, --))
>wm : Symbol(wm, Decl(acceptSymbolAsWeakType.ts, 7, 5))
>has : Symbol(WeakMap.has, Decl(lib.es2015.collection.d.ts, --, --))
>s : Symbol(s, Decl(acceptSymbolAsWeakType.ts, 0, 5))

wm.get(s);
>wm.get : Symbol(WeakMap.get, Decl(lib.es2015.collection.d.ts, --, --))
>wm : Symbol(wm, Decl(acceptSymbolAsWeakType.ts, 7, 5))
>get : Symbol(WeakMap.get, Decl(lib.es2015.collection.d.ts, --, --))
>s : Symbol(s, Decl(acceptSymbolAsWeakType.ts, 0, 5))

wm.delete(s);
>wm.delete : Symbol(WeakMap.delete, Decl(lib.es2015.collection.d.ts, --, --))
>wm : Symbol(wm, Decl(acceptSymbolAsWeakType.ts, 7, 5))
>delete : Symbol(WeakMap.delete, Decl(lib.es2015.collection.d.ts, --, --))
>s : Symbol(s, Decl(acceptSymbolAsWeakType.ts, 0, 5))

const wr = new WeakRef(s);
>wr : Symbol(wr, Decl(acceptSymbolAsWeakType.ts, 13, 5))
>WeakRef : Symbol(WeakRef, Decl(lib.es2021.weakref.d.ts, --, --), Decl(lib.es2021.weakref.d.ts, --, --))
>s : Symbol(s, Decl(acceptSymbolAsWeakType.ts, 0, 5))

wr.deref();
>wr.deref : Symbol(WeakRef.deref, Decl(lib.es2021.weakref.d.ts, --, --))
>wr : Symbol(wr, Decl(acceptSymbolAsWeakType.ts, 13, 5))
>deref : Symbol(WeakRef.deref, Decl(lib.es2021.weakref.d.ts, --, --))

const f = new FinalizationRegistry(() => {});
>f : Symbol(f, Decl(acceptSymbolAsWeakType.ts, 16, 5))
>FinalizationRegistry : Symbol(FinalizationRegistry, Decl(lib.es2021.weakref.d.ts, --, --), Decl(lib.es2021.weakref.d.ts, --, --))

f.register(s, null);
>f.register : Symbol(FinalizationRegistry.register, Decl(lib.es2021.weakref.d.ts, --, --))
>f : Symbol(f, Decl(acceptSymbolAsWeakType.ts, 16, 5))
>register : Symbol(FinalizationRegistry.register, Decl(lib.es2021.weakref.d.ts, --, --))
>s : Symbol(s, Decl(acceptSymbolAsWeakType.ts, 0, 5))

f.unregister(s);
>f.unregister : Symbol(FinalizationRegistry.unregister, Decl(lib.es2021.weakref.d.ts, --, --))
>f : Symbol(f, Decl(acceptSymbolAsWeakType.ts, 16, 5))
>unregister : Symbol(FinalizationRegistry.unregister, Decl(lib.es2021.weakref.d.ts, --, --))
>s : Symbol(s, Decl(acceptSymbolAsWeakType.ts, 0, 5))

Loading