Skip to content

Commit 26a350e

Browse files
committed
Migrate some files to TS
1 parent 402ac4f commit 26a350e

File tree

8 files changed

+206
-133
lines changed

8 files changed

+206
-133
lines changed

src/Hash.js renamed to src/Hash.ts

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@ import { smi } from './Math';
22

33
const defaultValueOf = Object.prototype.valueOf;
44

5-
export function hash(o) {
5+
export function hash(o: unknown): number {
66
// eslint-disable-next-line eqeqeq
77
if (o == null) {
88
return hashNullish(o);
99
}
1010

11+
// @ts-expect-error don't care about object beeing typed as `{}` here
1112
if (typeof o.hashCode === 'function') {
1213
// Drop any high bits from accidentally long hash codes.
14+
// @ts-expect-error don't care about object beeing typed as `{}` here
1315
return smi(o.hashCode(o));
1416
}
1517

@@ -45,12 +47,12 @@ export function hash(o) {
4547
}
4648
}
4749

48-
function hashNullish(nullish) {
50+
function hashNullish(nullish: null | undefined): number {
4951
return nullish === null ? 0x42108422 : /* undefined */ 0x42108423;
5052
}
5153

5254
// Compress arbitrarily large numbers into smi hashes.
53-
function hashNumber(n) {
55+
function hashNumber(n: number): number {
5456
if (n !== n || n === Infinity) {
5557
return 0;
5658
}
@@ -65,7 +67,7 @@ function hashNumber(n) {
6567
return smi(hash);
6668
}
6769

68-
function cachedHashString(string) {
70+
function cachedHashString(string: string): number {
6971
let hashed = stringHashCache[string];
7072
if (hashed === undefined) {
7173
hashed = hashString(string);
@@ -80,7 +82,7 @@ function cachedHashString(string) {
8082
}
8183

8284
// http://jsperf.com/hashing-strings
83-
function hashString(string) {
85+
function hashString(string: string): number {
8486
// This is the hash from JVM
8587
// The hash code for a string is computed as
8688
// s[0] * 31 ^ (n - 1) + s[1] * 31 ^ (n - 2) + ... + s[n - 1],
@@ -94,7 +96,7 @@ function hashString(string) {
9496
return smi(hashed);
9597
}
9698

97-
function hashSymbol(sym) {
99+
function hashSymbol(sym: symbol): number {
98100
let hashed = symbolMap[sym];
99101
if (hashed !== undefined) {
100102
return hashed;
@@ -107,21 +109,25 @@ function hashSymbol(sym) {
107109
return hashed;
108110
}
109111

110-
function hashJSObj(obj) {
111-
let hashed;
112+
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
113+
function hashJSObj(obj: object | Function): number {
114+
let hashed: number | undefined;
112115
if (usingWeakMap) {
116+
// @ts-expect-error weakMap is defined
113117
hashed = weakMap.get(obj);
114118
if (hashed !== undefined) {
115119
return hashed;
116120
}
117121
}
118122

123+
// @ts-expect-error used for old code, will be removed
119124
hashed = obj[UID_HASH_KEY];
120125
if (hashed !== undefined) {
121126
return hashed;
122127
}
123128

124129
if (!canDefineProperty) {
130+
// @ts-expect-error used for old code, will be removed
125131
hashed = obj.propertyIsEnumerable && obj.propertyIsEnumerable[UID_HASH_KEY];
126132
if (hashed !== undefined) {
127133
return hashed;
@@ -136,6 +142,7 @@ function hashJSObj(obj) {
136142
hashed = nextHash();
137143

138144
if (usingWeakMap) {
145+
// @ts-expect-error weakMap is defined
139146
weakMap.set(obj, hashed);
140147
} else if (isExtensible !== undefined && isExtensible(obj) === false) {
141148
throw new Error('Non-extensible objects are not allowed as keys.');
@@ -157,15 +164,19 @@ function hashJSObj(obj) {
157164
obj.propertyIsEnumerable = function () {
158165
return this.constructor.prototype.propertyIsEnumerable.apply(
159166
this,
167+
// eslint-disable-next-line prefer-rest-params
160168
arguments
161169
);
162170
};
171+
// @ts-expect-error used for old code, will be removed
163172
obj.propertyIsEnumerable[UID_HASH_KEY] = hashed;
173+
// @ts-expect-error used for old code, will be removed
164174
} else if (obj.nodeType !== undefined) {
165175
// At this point we couldn't get the IE `uniqueID` to use as a hash
166176
// and we couldn't use a non-enumerable property to exploit the
167177
// dontEnum bug so we simply add the `UID_HASH_KEY` on the node
168178
// itself.
179+
// @ts-expect-error used for old code, will be removed
169180
obj[UID_HASH_KEY] = hashed;
170181
} else {
171182
throw new Error('Unable to set a non-enumerable property on object.');
@@ -178,6 +189,7 @@ function hashJSObj(obj) {
178189
const isExtensible = Object.isExtensible;
179190

180191
// True if Object.defineProperty works as expected. IE8 fails this test.
192+
// TODO remove this as widely available https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
181193
const canDefineProperty = (function () {
182194
try {
183195
Object.defineProperty({}, '@', {});
@@ -190,24 +202,30 @@ const canDefineProperty = (function () {
190202

191203
// IE has a `uniqueID` property on DOM nodes. We can construct the hash from it
192204
// and avoid memory leaks from the IE cloneNode bug.
193-
function getIENodeHash(node) {
205+
// TODO remove this method as only used if `canDefineProperty` is false
206+
function getIENodeHash(node: unknown): number | undefined {
207+
// @ts-expect-error don't care
194208
if (node && node.nodeType > 0) {
209+
// @ts-expect-error don't care
195210
switch (node.nodeType) {
196211
case 1: // Element
212+
// @ts-expect-error don't care
197213
return node.uniqueID;
198214
case 9: // Document
215+
// @ts-expect-error don't care
199216
return node.documentElement && node.documentElement.uniqueID;
200217
}
201218
}
202219
}
203220

204-
function valueOf(obj) {
221+
function valueOf(obj: object): unknown {
205222
return obj.valueOf !== defaultValueOf && typeof obj.valueOf === 'function'
206-
? obj.valueOf(obj)
223+
? // @ts-expect-error weird the "obj" parameter as `valueOf` should not have a parameter
224+
obj.valueOf(obj)
207225
: obj;
208226
}
209227

210-
function nextHash() {
228+
function nextHash(): number {
211229
const nextHash = ++_objHashUID;
212230
if (_objHashUID & 0x40000000) {
213231
_objHashUID = 0;
@@ -216,8 +234,9 @@ function nextHash() {
216234
}
217235

218236
// If possible, use a WeakMap.
237+
// TODO using WeakMap should be true everywhere now that WeakMap is widely supported: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap
219238
const usingWeakMap = typeof WeakMap === 'function';
220-
let weakMap;
239+
let weakMap: WeakMap<object, number> | undefined;
221240
if (usingWeakMap) {
222241
weakMap = new WeakMap();
223242
}
@@ -226,12 +245,13 @@ const symbolMap = Object.create(null);
226245

227246
let _objHashUID = 0;
228247

229-
let UID_HASH_KEY = '__immutablehash__';
248+
// TODO remove string as Symbol is now widely supported: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol
249+
let UID_HASH_KEY: string | symbol = '__immutablehash__' as const;
230250
if (typeof Symbol === 'function') {
231251
UID_HASH_KEY = Symbol(UID_HASH_KEY);
232252
}
233253

234254
const STRING_HASH_CACHE_MIN_STRLEN = 16;
235255
const STRING_HASH_CACHE_MAX_SIZE = 255;
236256
let STRING_HASH_CACHE_SIZE = 0;
237-
let stringHashCache = {};
257+
let stringHashCache: { [key: string]: number } = {};

src/Iterator.js

Lines changed: 0 additions & 84 deletions
This file was deleted.

src/Iterator.ts

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
export const ITERATE_KEYS = 0;
2+
export const ITERATE_VALUES = 1;
3+
export const ITERATE_ENTRIES = 2;
4+
5+
type IteratorType =
6+
| typeof ITERATE_KEYS
7+
| typeof ITERATE_VALUES
8+
| typeof ITERATE_ENTRIES;
9+
10+
// TODO Symbol is widely available in modern JavaScript environments, clean this
11+
const REAL_ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator;
12+
const FAUX_ITERATOR_SYMBOL = '@@iterator';
13+
14+
export const ITERATOR_SYMBOL: string | symbol =
15+
REAL_ITERATOR_SYMBOL || FAUX_ITERATOR_SYMBOL;
16+
17+
export class Iterator<V> implements globalThis.Iterator<V> {
18+
static KEYS: number;
19+
static VALUES: number;
20+
static ENTRIES: number;
21+
next: () => IteratorResult<V>;
22+
inspect!: () => string;
23+
toSource!: () => string;
24+
25+
constructor(next: () => IteratorResult<V>) {
26+
this.next = next;
27+
}
28+
29+
toString() {
30+
return '[Iterator]';
31+
}
32+
}
33+
34+
Iterator.KEYS = ITERATE_KEYS;
35+
Iterator.VALUES = ITERATE_VALUES;
36+
Iterator.ENTRIES = ITERATE_ENTRIES;
37+
38+
Iterator.prototype.inspect = Iterator.prototype.toSource = function () {
39+
return this.toString();
40+
};
41+
// @ts-expect-error don't know how to type this
42+
Iterator.prototype[ITERATOR_SYMBOL] = function () {
43+
return this;
44+
};
45+
46+
export function iteratorValue<I>(
47+
type: IteratorType,
48+
k: any,
49+
v: any,
50+
iteratorResult: IteratorResult<I>
51+
): IteratorResult<I> {
52+
const value =
53+
type === ITERATE_KEYS ? k : type === ITERATE_VALUES ? v : [k, v];
54+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions -- TODO enable eslint here
55+
iteratorResult
56+
? (iteratorResult.value = value)
57+
: (iteratorResult = {
58+
value: value,
59+
done: false,
60+
});
61+
return iteratorResult;
62+
}
63+
64+
export function iteratorDone(): IteratorReturnResult<undefined> {
65+
return { value: undefined, done: true };
66+
}
67+
68+
export function hasIterator(
69+
maybeIterable: unknown
70+
): maybeIterable is Iterable<unknown> {
71+
if (Array.isArray(maybeIterable)) {
72+
// IE11 trick as it does not support `Symbol.iterator`
73+
return true;
74+
}
75+
76+
return !!getIteratorFn(maybeIterable);
77+
}
78+
79+
export function isIterator(
80+
maybeIterator: unknown
81+
): maybeIterator is Iterator<unknown> {
82+
return !!(
83+
maybeIterator &&
84+
// @ts-expect-error: maybeIterator is typed as `{}`
85+
typeof maybeIterator.next === 'function'
86+
);
87+
}
88+
89+
export function getIterator(iterable: unknown): Iterator<unknown> | undefined {
90+
const iteratorFn = getIteratorFn(iterable);
91+
return iteratorFn && iteratorFn.call(iterable);
92+
}
93+
94+
function getIteratorFn(
95+
iterable: unknown
96+
): (() => Iterator<unknown>) | undefined {
97+
const iteratorFn =
98+
iterable &&
99+
// @ts-expect-error: maybeIterator is typed as `{}`
100+
((REAL_ITERATOR_SYMBOL && iterable[REAL_ITERATOR_SYMBOL]) ||
101+
// @ts-expect-error: maybeIterator is typed as `{}`
102+
iterable[FAUX_ITERATOR_SYMBOL]);
103+
if (typeof iteratorFn === 'function') {
104+
return iteratorFn;
105+
}
106+
}
107+
108+
export function isEntriesIterable(
109+
maybeIterable: unknown
110+
): maybeIterable is Iterable<[unknown, unknown]> {
111+
const iteratorFn = getIteratorFn(maybeIterable);
112+
// @ts-expect-error: maybeIterator is typed as `{}`
113+
return iteratorFn && iteratorFn === maybeIterable.entries;
114+
}
115+
116+
export function isKeysIterable(
117+
maybeIterable: unknown
118+
): maybeIterable is Iterable<unknown> {
119+
const iteratorFn = getIteratorFn(maybeIterable);
120+
// @ts-expect-error: maybeIterator is typed as `{}`
121+
return iteratorFn && iteratorFn === maybeIterable.keys;
122+
}

0 commit comments

Comments
 (0)