Skip to content

Commit eeed721

Browse files
authored
Type definitions for 'Symbols as WeakMap keys' (#76) (#54195)
Signed-off-by: Leo Elmecker <lelmeckerpla@bloomberg.net>
1 parent 2f4962a commit eeed721

File tree

43 files changed

+777
-50
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+777
-50
lines changed

src/compiler/commandLineParser.ts

+2
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,9 @@ const libEntries: [string, string][] = [
212212
["es2022.string", "lib.es2022.string.d.ts"],
213213
["es2022.regexp", "lib.es2022.regexp.d.ts"],
214214
["es2023.array", "lib.es2023.array.d.ts"],
215+
["es2023.collection", "lib.es2023.collection.d.ts"],
215216
["esnext.array", "lib.es2023.array.d.ts"],
217+
["esnext.collection", "lib.es2023.collection.d.ts"],
216218
["esnext.symbol", "lib.es2019.symbol.d.ts"],
217219
["esnext.asynciterable", "lib.es2018.asynciterable.d.ts"],
218220
["esnext.intl", "lib.esnext.intl.d.ts"],

src/harness/fourslashInterfaceImpl.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1225,6 +1225,8 @@ export namespace Completion {
12251225
varEntry("Float64Array"),
12261226
interfaceEntry("Float64ArrayConstructor"),
12271227
moduleEntry("Intl"),
1228+
typeEntry("WeakKey"),
1229+
interfaceEntry("WeakKeyTypes"),
12281230
];
12291231

12301232
export const globalThisEntry: ExpectedCompletionEntry = {

src/lib/es2015.collection.d.ts

+9-9
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ interface ReadonlyMap<K, V> {
4242
readonly size: number;
4343
}
4444

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

6666
interface WeakMapConstructor {
67-
new <K extends object = object, V = any>(entries?: readonly (readonly [K, V])[] | null): WeakMap<K, V>;
68-
readonly prototype: WeakMap<object, any>;
67+
new <K extends WeakKey = WeakKey, V = any>(entries?: readonly [K, V][] | null): WeakMap<K, V>;
68+
readonly prototype: WeakMap<WeakKey, any>;
6969
}
7070
declare var WeakMap: WeakMapConstructor;
7171

@@ -107,9 +107,9 @@ interface ReadonlySet<T> {
107107
readonly size: number;
108108
}
109109

110-
interface WeakSet<T extends object> {
110+
interface WeakSet<T extends WeakKey> {
111111
/**
112-
* Appends a new object to the end of the WeakSet.
112+
* Appends a new value to the end of the WeakSet.
113113
*/
114114
add(value: T): this;
115115
/**
@@ -118,13 +118,13 @@ interface WeakSet<T extends object> {
118118
*/
119119
delete(value: T): boolean;
120120
/**
121-
* @returns a boolean indicating whether an object exists in the WeakSet or not.
121+
* @returns a boolean indicating whether a value exists in the WeakSet or not.
122122
*/
123123
has(value: T): boolean;
124124
}
125125

126126
interface WeakSetConstructor {
127-
new <T extends object = object>(values?: readonly T[] | null): WeakSet<T>;
128-
readonly prototype: WeakSet<object>;
127+
new <T extends WeakKey = WeakKey>(values?: readonly T[] | null): WeakSet<T>;
128+
readonly prototype: WeakSet<WeakKey>;
129129
}
130130
declare var WeakSet: WeakSetConstructor;

src/lib/es2015.iterable.d.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,10 @@ interface MapConstructor {
141141
new <K, V>(iterable?: Iterable<readonly [K, V]> | null): Map<K, V>;
142142
}
143143

144-
interface WeakMap<K extends object, V> { }
144+
interface WeakMap<K extends WeakKey, V> { }
145145

146146
interface WeakMapConstructor {
147-
new <K extends object, V>(iterable: Iterable<readonly [K, V]>): WeakMap<K, V>;
147+
new <K extends WeakKey, V>(iterable: Iterable<readonly [K, V]>): WeakMap<K, V>;
148148
}
149149

150150
interface Set<T> {
@@ -189,10 +189,10 @@ interface SetConstructor {
189189
new <T>(iterable?: Iterable<T> | null): Set<T>;
190190
}
191191

192-
interface WeakSet<T extends object> { }
192+
interface WeakSet<T extends WeakKey> { }
193193

194194
interface WeakSetConstructor {
195-
new <T extends object = object>(iterable: Iterable<T>): WeakSet<T>;
195+
new <T extends WeakKey = WeakKey>(iterable: Iterable<T>): WeakSet<T>;
196196
}
197197

198198
interface Promise<T> { }

src/lib/es2015.symbol.wellknown.d.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -119,15 +119,15 @@ interface Map<K, V> {
119119
readonly [Symbol.toStringTag]: string;
120120
}
121121

122-
interface WeakMap<K extends object, V> {
122+
interface WeakMap<K extends WeakKey, V> {
123123
readonly [Symbol.toStringTag]: string;
124124
}
125125

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

130-
interface WeakSet<T extends object> {
130+
interface WeakSet<T extends WeakKey> {
131131
readonly [Symbol.toStringTag]: string;
132132
}
133133

src/lib/es2021.weakref.d.ts

+19-16
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
interface WeakRef<T extends object> {
1+
interface WeakRef<T extends WeakKey> {
22
readonly [Symbol.toStringTag]: "WeakRef";
33

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

1415
/**
15-
* Creates a WeakRef instance for the given target object.
16-
* @param target The target object for the WeakRef instance.
16+
* Creates a WeakRef instance for the given target value.
17+
* In es2023 the value can be either a symbol or an object, in previous versions only object is permissible.
18+
* @param target The target value for the WeakRef instance.
1719
*/
18-
new<T extends object>(target: T): WeakRef<T>;
20+
new<T extends WeakKey>(target: T): WeakRef<T>;
1921
}
2022

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

2628
/**
27-
* Registers an object with the registry.
28-
* @param target The target object to register.
29-
* @param heldValue The value to pass to the finalizer for this object. This cannot be the
30-
* target object.
29+
* Registers a value with the registry.
30+
* In es2023 the value can be either a symbol or an object, in previous versions only object is permissible.
31+
* @param target The target value to register.
32+
* @param heldValue The value to pass to the finalizer for this value. This cannot be the
33+
* target value.
3134
* @param unregisterToken The token to pass to the unregister method to unregister the target
32-
* object. If provided (and not undefined), this must be an object. If not provided, the target
33-
* cannot be unregistered.
35+
* value. If not provided, the target cannot be unregistered.
3436
*/
35-
register(target: object, heldValue: T, unregisterToken?: object): void;
37+
register(target: WeakKey, heldValue: T, unregisterToken?: WeakKey): void;
3638

3739
/**
38-
* Unregisters an object from the registry.
40+
* Unregisters a value from the registry.
41+
* In es2023 the value can be either a symbol or an object, in previous versions only object is permissible.
3942
* @param unregisterToken The token that was used as the unregisterToken argument when calling
40-
* register to register the target object.
43+
* register to register the target value.
4144
*/
42-
unregister(unregisterToken: object): void;
45+
unregister(unregisterToken: WeakKey): void;
4346
}
4447

4548
interface FinalizationRegistryConstructor {
4649
readonly prototype: FinalizationRegistry<any>;
4750

4851
/**
4952
* Creates a finalization registry with an associated cleanup callback
50-
* @param cleanupCallback The callback to call after an object in the registry has been reclaimed.
53+
* @param cleanupCallback The callback to call after a value in the registry has been reclaimed.
5154
*/
5255
new<T>(cleanupCallback: (heldValue: T) => void): FinalizationRegistry<T>;
5356
}

src/lib/es2023.collection.d.ts

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
interface WeakKeyTypes {
2+
symbol: symbol;
3+
}

src/lib/es2023.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
/// <reference lib="es2022" />
22
/// <reference lib="es2023.array" />
3+
/// <reference lib="es2023.collection" />

src/lib/es5.d.ts

+9
Original file line numberDiff line numberDiff line change
@@ -1647,6 +1647,15 @@ type Uncapitalize<S extends string> = intrinsic;
16471647
*/
16481648
interface ThisType<T> { }
16491649

1650+
/**
1651+
* Stores types to be used with WeakSet, WeakMap, WeakRef, and FinalizationRegistry
1652+
*/
1653+
interface WeakKeyTypes {
1654+
object: object;
1655+
}
1656+
1657+
type WeakKey = WeakKeyTypes[keyof WeakKeyTypes];
1658+
16501659
/**
16511660
* Represents a raw buffer of binary data, which is used to store data for the
16521661
* different typed arrays. ArrayBuffers cannot be read from or written to directly,

src/lib/libs.json

+1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
"es2022.string",
6767
"es2022.regexp",
6868
"es2023.array",
69+
"es2023.collection",
6970
"esnext.intl",
7071
"decorators",
7172
"decorators.legacy",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//// [tests/cases/compiler/acceptSymbolAsWeakType.ts] ////
2+
3+
//// [acceptSymbolAsWeakType.ts]
4+
const s: symbol = Symbol('s');
5+
6+
const ws = new WeakSet([s]);
7+
ws.add(s);
8+
ws.has(s);
9+
ws.delete(s);
10+
11+
const wm = new WeakMap([[s, false]]);
12+
wm.set(s, true);
13+
wm.has(s);
14+
wm.get(s);
15+
wm.delete(s);
16+
17+
const wr = new WeakRef(s);
18+
wr.deref();
19+
20+
const f = new FinalizationRegistry(() => {});
21+
f.register(s, null);
22+
f.unregister(s);
23+
24+
//// [acceptSymbolAsWeakType.js]
25+
"use strict";
26+
const s = Symbol('s');
27+
const ws = new WeakSet([s]);
28+
ws.add(s);
29+
ws.has(s);
30+
ws.delete(s);
31+
const wm = new WeakMap([[s, false]]);
32+
wm.set(s, true);
33+
wm.has(s);
34+
wm.get(s);
35+
wm.delete(s);
36+
const wr = new WeakRef(s);
37+
wr.deref();
38+
const f = new FinalizationRegistry(() => { });
39+
f.register(s, null);
40+
f.unregister(s);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
//// [tests/cases/compiler/acceptSymbolAsWeakType.ts] ////
2+
3+
=== acceptSymbolAsWeakType.ts ===
4+
const s: symbol = Symbol('s');
5+
>s : Symbol(s, Decl(acceptSymbolAsWeakType.ts, 0, 5))
6+
>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, --, --))
7+
8+
const ws = new WeakSet([s]);
9+
>ws : Symbol(ws, Decl(acceptSymbolAsWeakType.ts, 2, 5))
10+
>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, --, --))
11+
>s : Symbol(s, Decl(acceptSymbolAsWeakType.ts, 0, 5))
12+
13+
ws.add(s);
14+
>ws.add : Symbol(WeakSet.add, Decl(lib.es2015.collection.d.ts, --, --))
15+
>ws : Symbol(ws, Decl(acceptSymbolAsWeakType.ts, 2, 5))
16+
>add : Symbol(WeakSet.add, Decl(lib.es2015.collection.d.ts, --, --))
17+
>s : Symbol(s, Decl(acceptSymbolAsWeakType.ts, 0, 5))
18+
19+
ws.has(s);
20+
>ws.has : Symbol(WeakSet.has, Decl(lib.es2015.collection.d.ts, --, --))
21+
>ws : Symbol(ws, Decl(acceptSymbolAsWeakType.ts, 2, 5))
22+
>has : Symbol(WeakSet.has, Decl(lib.es2015.collection.d.ts, --, --))
23+
>s : Symbol(s, Decl(acceptSymbolAsWeakType.ts, 0, 5))
24+
25+
ws.delete(s);
26+
>ws.delete : Symbol(WeakSet.delete, Decl(lib.es2015.collection.d.ts, --, --))
27+
>ws : Symbol(ws, Decl(acceptSymbolAsWeakType.ts, 2, 5))
28+
>delete : Symbol(WeakSet.delete, Decl(lib.es2015.collection.d.ts, --, --))
29+
>s : Symbol(s, Decl(acceptSymbolAsWeakType.ts, 0, 5))
30+
31+
const wm = new WeakMap([[s, false]]);
32+
>wm : Symbol(wm, Decl(acceptSymbolAsWeakType.ts, 7, 5))
33+
>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, --, --))
34+
>s : Symbol(s, Decl(acceptSymbolAsWeakType.ts, 0, 5))
35+
36+
wm.set(s, true);
37+
>wm.set : Symbol(WeakMap.set, Decl(lib.es2015.collection.d.ts, --, --))
38+
>wm : Symbol(wm, Decl(acceptSymbolAsWeakType.ts, 7, 5))
39+
>set : Symbol(WeakMap.set, Decl(lib.es2015.collection.d.ts, --, --))
40+
>s : Symbol(s, Decl(acceptSymbolAsWeakType.ts, 0, 5))
41+
42+
wm.has(s);
43+
>wm.has : Symbol(WeakMap.has, Decl(lib.es2015.collection.d.ts, --, --))
44+
>wm : Symbol(wm, Decl(acceptSymbolAsWeakType.ts, 7, 5))
45+
>has : Symbol(WeakMap.has, Decl(lib.es2015.collection.d.ts, --, --))
46+
>s : Symbol(s, Decl(acceptSymbolAsWeakType.ts, 0, 5))
47+
48+
wm.get(s);
49+
>wm.get : Symbol(WeakMap.get, Decl(lib.es2015.collection.d.ts, --, --))
50+
>wm : Symbol(wm, Decl(acceptSymbolAsWeakType.ts, 7, 5))
51+
>get : Symbol(WeakMap.get, Decl(lib.es2015.collection.d.ts, --, --))
52+
>s : Symbol(s, Decl(acceptSymbolAsWeakType.ts, 0, 5))
53+
54+
wm.delete(s);
55+
>wm.delete : Symbol(WeakMap.delete, Decl(lib.es2015.collection.d.ts, --, --))
56+
>wm : Symbol(wm, Decl(acceptSymbolAsWeakType.ts, 7, 5))
57+
>delete : Symbol(WeakMap.delete, Decl(lib.es2015.collection.d.ts, --, --))
58+
>s : Symbol(s, Decl(acceptSymbolAsWeakType.ts, 0, 5))
59+
60+
const wr = new WeakRef(s);
61+
>wr : Symbol(wr, Decl(acceptSymbolAsWeakType.ts, 13, 5))
62+
>WeakRef : Symbol(WeakRef, Decl(lib.es2021.weakref.d.ts, --, --), Decl(lib.es2021.weakref.d.ts, --, --))
63+
>s : Symbol(s, Decl(acceptSymbolAsWeakType.ts, 0, 5))
64+
65+
wr.deref();
66+
>wr.deref : Symbol(WeakRef.deref, Decl(lib.es2021.weakref.d.ts, --, --))
67+
>wr : Symbol(wr, Decl(acceptSymbolAsWeakType.ts, 13, 5))
68+
>deref : Symbol(WeakRef.deref, Decl(lib.es2021.weakref.d.ts, --, --))
69+
70+
const f = new FinalizationRegistry(() => {});
71+
>f : Symbol(f, Decl(acceptSymbolAsWeakType.ts, 16, 5))
72+
>FinalizationRegistry : Symbol(FinalizationRegistry, Decl(lib.es2021.weakref.d.ts, --, --), Decl(lib.es2021.weakref.d.ts, --, --))
73+
74+
f.register(s, null);
75+
>f.register : Symbol(FinalizationRegistry.register, Decl(lib.es2021.weakref.d.ts, --, --))
76+
>f : Symbol(f, Decl(acceptSymbolAsWeakType.ts, 16, 5))
77+
>register : Symbol(FinalizationRegistry.register, Decl(lib.es2021.weakref.d.ts, --, --))
78+
>s : Symbol(s, Decl(acceptSymbolAsWeakType.ts, 0, 5))
79+
80+
f.unregister(s);
81+
>f.unregister : Symbol(FinalizationRegistry.unregister, Decl(lib.es2021.weakref.d.ts, --, --))
82+
>f : Symbol(f, Decl(acceptSymbolAsWeakType.ts, 16, 5))
83+
>unregister : Symbol(FinalizationRegistry.unregister, Decl(lib.es2021.weakref.d.ts, --, --))
84+
>s : Symbol(s, Decl(acceptSymbolAsWeakType.ts, 0, 5))
85+

0 commit comments

Comments
 (0)