Repository: League-of-Foundry-Developers/foundry-vtt-types
Pull request #3093 (2025-02-14 21:25:07)

Common tests
primitives and utils


Patch:
diff --git a/src/foundry/common/primitives/regex.d.mts b/src/foundry/common/primitives/regex.d.mts
deleted file mode 100644
index 7c09c7a2e..000000000
--- a/src/foundry/common/primitives/regex.d.mts
+++ /dev/null
@@ -1,12 +0,0 @@
-export {};
-
-declare global {
-  interface RegExpConstructor {
-    /**
-     * Escape a given input string, prefacing special characters with backslashes for use in a regular expression
-     * @param string - The un-escaped input string
-     * @returns The escaped string, suitable for use in regular expression
-     */
-    escape(string: string): string;
-  }
-}
diff --git a/src/foundry/common/utils/bitmask.d.mts b/src/foundry/common/utils/bitmask.d.mts
index d67092ed1..e0b15f2f0 100644
--- a/src/foundry/common/utils/bitmask.d.mts
+++ b/src/foundry/common/utils/bitmask.d.mts
@@ -1,9 +1,9 @@
-declare class InternalBitMask extends Number {
+declare class InternalBitMask<T extends Record<string, boolean>> extends Number {
   /**
    * Create a new BitMask instance.
    * @param states    - An object containing valid states and their corresponding initial boolean values (default is null).
    */
-  constructor(states?: Record<string, boolean> | null);
+  constructor(states?: T | null);
 
   // a placeholder private method to help subclassing
   #bitmask: true;
@@ -12,7 +12,7 @@ declare class InternalBitMask extends Number {
    * The enum associated with this structure.
    * @readonly
    */
-  states: Record<string, string>;
+  states: Readonly<{ [K in keyof T]: K }>;
 
   /**
    * True if this bitmask is empty (no active states).
@@ -24,33 +24,33 @@ declare class InternalBitMask extends Number {
    * @param state   - The state to check.
    * @returns True if the state is active, false otherwise.
    */
-  hasState(state: string): boolean;
+  hasState(state: keyof T): boolean;
 
   /**
    * Add a state to the bitmask.
    * @param state - The state to add. Throws an error if the provided state is not valid.
    */
-  addState(state: string): void;
+  addState(state: keyof T): void;
 
   /**
    * Remove a state from the bitmask.
    * @param state   - The state to remove. Throws an error if the provided state is not valid.
    */
-  removeState(state: string): void;
+  removeState(state: keyof T): void;
 
   /**
    * Toggle the state of a specific state in the bitmask.
    * @param state   - The state to toggle. Throws an error if the provided state is not valid.
    * @param enabled - Toggle on (true) or off (false)? If undefined, the state is switched automatically.
    */
-  toggleState(state: string, enabled: boolean): void;
+  toggleState(state: keyof T, enabled: boolean): void;
 
   /**
    * Toggle the state of a specific state in the bitmask.
    * @param state - The state to toggle.
    * @returns  The updated bitmask. Throws an error if the provided state is not valid.
    */
-  toggleState(state: string): number;
+  toggleState(state: keyof T): number;
 
   /**
    * Clear the bitmask, setting all states to inactive.
@@ -74,7 +74,7 @@ declare class InternalBitMask extends Number {
    * @param otherBitMask  - The bitmask structure to compare with.
    * @returns True if the two bitmasks have the same structure, false otherwise.
    */
-  isCompatible(otherBitMask: BitMask): boolean;
+  isCompatible(otherBitMask: BitMask.Any): boolean;
 
   /**
    * Serializes the bitmask to a JSON string.
@@ -87,7 +87,7 @@ declare class InternalBitMask extends Number {
    * @param jsonString    - The JSON string representing the bitmask.
    * @returns A new BitMask instance created from the JSON string.
    */
-  static fromJSON(jsonString: string): BitMask;
+  static fromJSON(jsonString: string): BitMask.Any;
 
   /**
    * Convert value of this BitMask to object representation according to structure.
@@ -99,7 +99,7 @@ declare class InternalBitMask extends Number {
    * Creates a clone of this BitMask instance.
    * @returns A new BitMask instance with the same value and valid states as this instance.
    */
-  clone(): BitMask;
+  clone(): this;
 
   /**
    * Generates shader constants based on the provided states.
@@ -109,7 +109,11 @@ declare class InternalBitMask extends Number {
   static generateShaderBitMaskConstants(states: string[]): string;
 }
 
+declare namespace BitMask {
+  export type Any = InternalBitMask<Record<string, boolean>>;
+}
+
 declare const BitMask: typeof InternalBitMask & (new (...args: any) => number);
-type BitMask = InternalBitMask & number;
+type BitMask = BitMask.Any & number;
 
 export default BitMask;
diff --git a/src/foundry/common/utils/color.d.mts b/src/foundry/common/utils/color.d.mts
index 519131df9..b32276a62 100644
--- a/src/foundry/common/utils/color.d.mts
+++ b/src/foundry/common/utils/color.d.mts
@@ -268,6 +268,15 @@ declare class InternalColor extends PatchedNumber {
    */
   static fromRGB(rgb: Color.RGBColorVector): Color;
 
+  /**
+   * Create a Color instance from an RGB normalized values.
+   * @param r - The red value
+   * @param g - The green value
+   * @param b - The blue value
+   * @returns The hex color instance
+   */
+  static fromRGBvalues(r: number, g: number, b: number): Color;
+
   /**
    * Create a Color instance from an HSV array.
    * Conversion formula adapted from {@link http://en.wikipedia.org/wiki/HSV_color_space}.
diff --git a/src/foundry/common/utils/helpers.d.mts b/src/foundry/common/utils/helpers.d.mts
index ef05272b4..9700ba06c 100644
--- a/src/foundry/common/utils/helpers.d.mts
+++ b/src/foundry/common/utils/helpers.d.mts
@@ -1,4 +1,4 @@
-import type { AnyConstructor, AnyFunction, DeepPartial, InexactPartial } from "fvtt-types/utils";
+import type { AnyConstructor, AnyFunction, DeepPartial, InexactPartial, NonNullish } from "fvtt-types/utils";
 import type Document from "../abstract/document.d.mts";
 
 /**
@@ -304,7 +304,10 @@ export function isNewerVersion(v1: number | string, v0: number | string): boolea
  * @param value - The value to test
  * @returns Is the value empty-like?
  */
-export function isEmpty(value: undefined | null | unknown[] | object | Set<unknown> | Map<unknown, unknown>): boolean;
+
+export function isEmpty(
+  value: undefined | null | unknown[] | object | Set<unknown> | Map<unknown, unknown> | NonNullish,
+): boolean;
 
 export type MergeObject<T, U, M extends MergeObjectOptions> = UpdateInsert<
   DeleteByObjectKeys<T, U, M>,
@@ -470,7 +473,7 @@ export function timeSince(timeStamp: Date | string): string;
  * @param options - Additional options. (default: `{}`)
  * @returns
  */
-export function formatFileSize(size: number, options: FormatFileSizeOptions): string;
+export function formatFileSize(size: number, options?: FormatFileSizeOptions): string;
 
 interface FormatFileSizeOptions {
   /**


Test patch:
diff --git a/tests/foundry/client/head.test-d.ts b/tests/foundry/client/head.test-d.ts
index d71d551b0..c393abfae 100644
--- a/tests/foundry/client/head.test-d.ts
+++ b/tests/foundry/client/head.test-d.ts
@@ -7,4 +7,4 @@ expectTypeOf(ui.menu).toEqualTypeOf<MainMenu | undefined>();
 
 const myColor = Color.from("foobar");
 
-expectTypeOf(myColor).toEqualTypeOf<number | Color>();
+expectTypeOf(myColor).toEqualTypeOf<Color>();
diff --git a/tests/foundry/common/primitives/array.mjs.test-d.ts b/tests/foundry/common/primitives/array.test-d.ts
similarity index 75%
rename from tests/foundry/common/primitives/array.mjs.test-d.ts
rename to tests/foundry/common/primitives/array.test-d.ts
index ef07102f6..ecf21375e 100644
--- a/tests/foundry/common/primitives/array.mjs.test-d.ts
+++ b/tests/foundry/common/primitives/array.test-d.ts
@@ -3,7 +3,12 @@ import { expectTypeOf } from "vitest";
 expectTypeOf([["testing"], [["test"], ["test"]], "test"].deepFlatten()).toEqualTypeOf<string[]>();
 expectTypeOf([["testing"], [[3], [4]], "test"].deepFlatten()).toEqualTypeOf<Array<string | number>>();
 
+expectTypeOf([].equals([])).toEqualTypeOf<boolean>();
+
 expectTypeOf(Array<"a" | "b">().partition((val): val is "b" => val === "b")).toEqualTypeOf<["a"[], "b"[]]>();
 expectTypeOf([1, ""].partition((val): val is string => typeof val === "string")).toEqualTypeOf<[number[], string[]]>();
 expectTypeOf(Array<string>().partition((val): boolean => val.length < 5)).toEqualTypeOf<[string[], string[]]>();
 expectTypeOf(Array<string>().partition((val) => val.length < 5)).toEqualTypeOf<[string[], string[]]>();
+
+expectTypeOf([].filterJoin("")).toEqualTypeOf<string>();
+expectTypeOf(["a"].findSplice((_val: string, _i: number, _obj: string[]) => true)).toEqualTypeOf<string | null>();
diff --git a/tests/foundry/common/primitives/date.test-d.ts b/tests/foundry/common/primitives/date.test-d.ts
new file mode 100644
index 000000000..193f64e83
--- /dev/null
+++ b/tests/foundry/common/primitives/date.test-d.ts
@@ -0,0 +1,7 @@
+import { expectTypeOf } from "vitest";
+
+declare const date: Date;
+
+expectTypeOf(date.isValid()).toEqualTypeOf<boolean>();
+expectTypeOf(date.toDateInputString()).toEqualTypeOf<string>();
+expectTypeOf(date.toTimeInputString()).toEqualTypeOf<string>();
diff --git a/tests/foundry/common/primitives/math.mjs.test-d.ts b/tests/foundry/common/primitives/math.test-d.ts
similarity index 92%
rename from tests/foundry/common/primitives/math.mjs.test-d.ts
rename to tests/foundry/common/primitives/math.test-d.ts
index 6ffd6be0e..427e9ef58 100644
--- a/tests/foundry/common/primitives/math.mjs.test-d.ts
+++ b/tests/foundry/common/primitives/math.test-d.ts
@@ -13,6 +13,8 @@ expectTypeOf(Math.normalizeDegrees(240)).toEqualTypeOf<number>();
 
 expectTypeOf(Math.normalizeRadians(4.18879)).toEqualTypeOf<number>();
 
+expectTypeOf(Math.roundDecimals(4.18879, 2)).toEqualTypeOf<number>();
+
 expectTypeOf(Math.toDegrees(4.18879)).toEqualTypeOf<number>();
 
 expectTypeOf(Math.toRadians(240)).toEqualTypeOf<number>();
diff --git a/tests/foundry/common/primitives/number.test-d.ts b/tests/foundry/common/primitives/number.test-d.ts
new file mode 100644
index 000000000..35fd03cb6
--- /dev/null
+++ b/tests/foundry/common/primitives/number.test-d.ts
@@ -0,0 +1,9 @@
+import { expectTypeOf } from "vitest";
+
+declare const num: number;
+
+expectTypeOf(num.almostEqual(3)).toEqualTypeOf<boolean>();
+expectTypeOf(num.ordinalString()).toEqualTypeOf<string>();
+expectTypeOf(num.paddedString(3)).toEqualTypeOf<string>();
+expectTypeOf(num.toNearest()).toEqualTypeOf<number>();
+expectTypeOf(num.between(3, 5)).toEqualTypeOf<boolean>();
diff --git a/tests/foundry/common/primitives/regexp.test-d.ts b/tests/foundry/common/primitives/regexp.test-d.ts
new file mode 100644
index 000000000..f72b30225
--- /dev/null
+++ b/tests/foundry/common/primitives/regexp.test-d.ts
@@ -0,0 +1,5 @@
+import { expectTypeOf } from "vitest";
+
+declare const regExpConstructor: RegExpConstructor;
+
+expectTypeOf(regExpConstructor.escape("3")).toEqualTypeOf<string>();
diff --git a/tests/foundry/common/primitives/set.mjs.test-d.ts b/tests/foundry/common/primitives/set.mjs.test-d.ts
deleted file mode 100644
index 6830170ce..000000000
--- a/tests/foundry/common/primitives/set.mjs.test-d.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { expectTypeOf } from "vitest";
-
-expectTypeOf(new Set<number | string>().filter((value): value is string => typeof value === "string")).toEqualTypeOf<
-  Set<string>
->();
-expectTypeOf(new Set<"a" | "b">().filter((value): value is "a" => value === "a")).toEqualTypeOf<Set<"a">>();
-
-expectTypeOf(new Set<number>().find((value) => value > 5)).toEqualTypeOf<number | undefined>();
-expectTypeOf(new Set<number | string>().find((value): value is number => typeof value === "number")).toEqualTypeOf<
-  number | undefined
->();
-expectTypeOf(new Set<"a" | "b">().find((value): value is "a" => value === "a")).toEqualTypeOf<"a" | undefined>();
diff --git a/tests/foundry/common/primitives/set.test-d.ts b/tests/foundry/common/primitives/set.test-d.ts
new file mode 100644
index 000000000..2658e4199
--- /dev/null
+++ b/tests/foundry/common/primitives/set.test-d.ts
@@ -0,0 +1,37 @@
+import { expectTypeOf } from "vitest";
+
+declare const set: Set<string>;
+declare const set2: Set<string>;
+
+expectTypeOf(set.difference(set2)).toEqualTypeOf<Set<string>>();
+expectTypeOf(set.equals(set2)).toEqualTypeOf<boolean>();
+expectTypeOf(set.first()).toEqualTypeOf<string | undefined>();
+expectTypeOf(set.intersection(set2)).toEqualTypeOf<Set<string>>();
+expectTypeOf(set.intersects(set2)).toEqualTypeOf<boolean>();
+expectTypeOf(set.intersects(set2)).toEqualTypeOf<boolean>();
+expectTypeOf(set.toObject()).toEqualTypeOf<string[]>();
+expectTypeOf(set.every((_val: string, _idx: number, _set: Set<string>) => true)).toEqualTypeOf<boolean>();
+
+expectTypeOf(new Set<number | string>().filter((value): value is string => typeof value === "string")).toEqualTypeOf<
+  Set<string>
+>();
+expectTypeOf(new Set<"a" | "b">().filter((value): value is "a" => value === "a")).toEqualTypeOf<Set<"a">>();
+
+expectTypeOf(new Set<number>().find((value) => value > 5)).toEqualTypeOf<number | undefined>();
+expectTypeOf(new Set<number | string>().find((value): value is number => typeof value === "number")).toEqualTypeOf<
+  number | undefined
+>();
+expectTypeOf(new Set<"a" | "b">().find((value): value is "a" => value === "a")).toEqualTypeOf<"a" | undefined>();
+
+expectTypeOf(set.map((_v: string, _i: number, _s: Set<string>) => true)).toEqualTypeOf<Set<boolean>>();
+
+type ReduceType = {
+  foo: string;
+};
+expectTypeOf(
+  set.reduce((_a: ReduceType, _v: string, _i: number, _s: Set<string>): ReduceType => ({ foo: "a" }), {
+    foo: "a",
+  } as ReduceType),
+).toEqualTypeOf<ReduceType>();
+
+expectTypeOf(set.some((_v: string, _i: number, _s: Set<string>) => true)).toEqualTypeOf<boolean>();
diff --git a/tests/foundry/common/primitives/string.mjs.test-d.ts b/tests/foundry/common/primitives/string.test-d.ts
similarity index 73%
rename from tests/foundry/common/primitives/string.mjs.test-d.ts
rename to tests/foundry/common/primitives/string.test-d.ts
index f694b5ba3..0a14ae63f 100644
--- a/tests/foundry/common/primitives/string.mjs.test-d.ts
+++ b/tests/foundry/common/primitives/string.test-d.ts
@@ -5,7 +5,12 @@ expectTypeOf("FOO".capitalize()).toEqualTypeOf<"FOO">();
 expectTypeOf("foo bar".capitalize()).toEqualTypeOf<"Foo bar">();
 expectTypeOf("FOO BAR".capitalize()).toEqualTypeOf<"FOO BAR">();
 
+expectTypeOf("FOO BAR".compare("")).toEqualTypeOf<number>();
+
 expectTypeOf("foo".titleCase()).toEqualTypeOf<"Foo">();
 expectTypeOf("FOO".titleCase()).toEqualTypeOf<"Foo">();
 expectTypeOf("foo bar".titleCase()).toEqualTypeOf<"Foo Bar">();
 expectTypeOf("FOO BAR".titleCase()).toEqualTypeOf<"Foo Bar">();
+
+expectTypeOf("FOO BAR".stripScripts()).toEqualTypeOf<string>();
+expectTypeOf("FOO BAR".slugify()).toEqualTypeOf<string>();
diff --git a/tests/foundry/common/primitives/url.test-d.ts b/tests/foundry/common/primitives/url.test-d.ts
new file mode 100644
index 000000000..4f6d54d4e
--- /dev/null
+++ b/tests/foundry/common/primitives/url.test-d.ts
@@ -0,0 +1,1 @@
+// no tests
diff --git a/tests/foundry/common/utils/bitmask.mjs.test-d.ts b/tests/foundry/common/utils/bitmask.mjs.test-d.ts
deleted file mode 100644
index 32e8d26d5..000000000
--- a/tests/foundry/common/utils/bitmask.mjs.test-d.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import { expectTypeOf } from "vitest";
-
-const b = new foundry.utils.BitMask();
-const _number: number = b;
-
-expectTypeOf(b.hasState("a")).toEqualTypeOf<boolean>();
-expectTypeOf(b.addState("a")).toEqualTypeOf<void>();
-expectTypeOf(b.removeState("a")).toEqualTypeOf<void>();
-
-expectTypeOf(b.toggleState("a", true)).toEqualTypeOf<void>();
-expectTypeOf(b.toggleState("a")).toEqualTypeOf<number>();
-
-expectTypeOf(b.clear()).toEqualTypeOf<void>();
-expectTypeOf(b.valueOf()).toEqualTypeOf<number>();
-expectTypeOf(b.toString()).toEqualTypeOf<string>();
-
-const b2 = new foundry.utils.BitMask({ a: true });
-expectTypeOf(b.isCompatible(b2)).toEqualTypeOf<boolean>();
-
-expectTypeOf(b.toJSON()).toEqualTypeOf<string>();
-
-expectTypeOf(foundry.utils.BitMask.fromJSON("{a: true}")).toEqualTypeOf<foundry.utils.BitMask>();
-expectTypeOf(b.toObject()).toEqualTypeOf<Record<string, boolean>>();
-expectTypeOf(b.clone()).toEqualTypeOf<foundry.utils.BitMask>();
-
-expectTypeOf(foundry.utils.BitMask.generateShaderBitMaskConstants(["a"])).toEqualTypeOf<string>();
diff --git a/tests/foundry/common/utils/bitmask.test-d.ts b/tests/foundry/common/utils/bitmask.test-d.ts
new file mode 100644
index 000000000..e0b7cd9a8
--- /dev/null
+++ b/tests/foundry/common/utils/bitmask.test-d.ts
@@ -0,0 +1,48 @@
+import { expect, expectTypeOf } from "vitest";
+
+const b = new foundry.utils.BitMask({ foo: true, bar: false });
+
+// test assignability to number
+const n: number = b;
+
+expect(n).toBe(1);
+
+expectTypeOf(b.states).toEqualTypeOf<
+  Readonly<{
+    foo: "foo";
+    bar: "bar";
+  }>
+>();
+expectTypeOf(b.isEmpty).toEqualTypeOf<boolean>();
+
+// @ts-expect-error - only valid states should work
+expectTypeOf(b.hasState("a")).toEqualTypeOf<boolean>();
+expectTypeOf(b.hasState("foo")).toEqualTypeOf<boolean>();
+
+// @ts-expect-error - only valid states should work
+expectTypeOf(b.addState("a")).toEqualTypeOf<void>();
+expectTypeOf(b.addState("foo")).toEqualTypeOf<void>();
+
+// @ts-expect-error - only valid states should work
+expectTypeOf(b.removeState("a")).toEqualTypeOf<void>();
+expectTypeOf(b.removeState("bar")).toEqualTypeOf<void>();
+
+// @ts-expect-error - only valid states should work
+expectTypeOf(b.toggleState("a", true)).toEqualTypeOf<void>();
+expectTypeOf(b.toggleState("bar")).toEqualTypeOf<number>();
+expectTypeOf(b.toggleState("foo", true)).toEqualTypeOf<void>();
+
+expectTypeOf(b.clear()).toEqualTypeOf<void>();
+expectTypeOf(b.valueOf()).toEqualTypeOf<number>();
+expectTypeOf(b.toString()).toEqualTypeOf<string>();
+
+const b2 = new foundry.utils.BitMask({ a: true });
+expectTypeOf(b.isCompatible(b2)).toEqualTypeOf<boolean>();
+
+expectTypeOf(b.toJSON()).toEqualTypeOf<string>();
+
+expectTypeOf(foundry.utils.BitMask.fromJSON('{"a": true}')).toEqualTypeOf<foundry.utils.BitMask.Any>();
+expectTypeOf(b.toObject()).toEqualTypeOf<Record<string, boolean>>();
+expectTypeOf(b.clone()).toEqualTypeOf<typeof b>();
+
+expectTypeOf(foundry.utils.BitMask.generateShaderBitMaskConstants(["a"])).toEqualTypeOf<string>();
diff --git a/tests/foundry/common/utils/collection.mjs.test-d.ts b/tests/foundry/common/utils/collection.test-d.ts
similarity index 87%
rename from tests/foundry/common/utils/collection.mjs.test-d.ts
rename to tests/foundry/common/utils/collection.test-d.ts
index 1511cb2c0..79bbe60fb 100644
--- a/tests/foundry/common/utils/collection.mjs.test-d.ts
+++ b/tests/foundry/common/utils/collection.test-d.ts
@@ -2,6 +2,16 @@ import { expectTypeOf } from "vitest";
 
 const c = new Collection<string>();
 
+expectTypeOf(c.contents).toEqualTypeOf<string[]>();
+
+expectTypeOf(c.toJSON()).toEqualTypeOf<string[]>();
+
+const c2 = new Collection<{
+  toJSON(): boolean;
+}>();
+
+expectTypeOf(c2.toJSON()).toEqualTypeOf<boolean[]>();
+
 expectTypeOf(c.get("")).toEqualTypeOf<string | undefined>();
 expectTypeOf(c.get("", { strict: false })).toEqualTypeOf<string | undefined>();
 expectTypeOf(c.get("", { strict: true })).toEqualTypeOf<string>();
diff --git a/tests/foundry/common/utils/color.mjs.test-d.mts b/tests/foundry/common/utils/color.mjs.test-d.mts
deleted file mode 100644
index 97837d0ab..000000000
--- a/tests/foundry/common/utils/color.mjs.test-d.mts
+++ /dev/null
@@ -1,2 +0,0 @@
-const _color1: number = new Color(0xffffff);
-const _color2: number = Color.from(0xffff00);
diff --git a/tests/foundry/common/utils/color.test-d.ts b/tests/foundry/common/utils/color.test-d.ts
new file mode 100644
index 000000000..f85c9196e
--- /dev/null
+++ b/tests/foundry/common/utils/color.test-d.ts
@@ -0,0 +1,51 @@
+import { expectTypeOf } from "vitest";
+
+// test assignability to number
+const _color1: number = new Color(0xffffff);
+const _color2: number = Color.from(0xffff00);
+
+const color = new Color();
+
+expectTypeOf(color.valid).toEqualTypeOf<boolean>();
+expectTypeOf(color.css).toEqualTypeOf<string>();
+expectTypeOf(color.rgb).toEqualTypeOf<Color.RGBColorVector>();
+expectTypeOf(color.r).toEqualTypeOf<number>();
+expectTypeOf(color.g).toEqualTypeOf<number>();
+expectTypeOf(color.b).toEqualTypeOf<number>();
+expectTypeOf(color.maximum).toEqualTypeOf<number>();
+expectTypeOf(color.minimum).toEqualTypeOf<number>();
+expectTypeOf(color.littleEndian).toEqualTypeOf<number>();
+expectTypeOf(color.hsv).toEqualTypeOf<Color.HSVColorVector>();
+expectTypeOf(color.hsl).toEqualTypeOf<Color.HSLColorVector>();
+expectTypeOf(color.linear).toEqualTypeOf<Color.RGBColorVector>();
+expectTypeOf(color.toJSON()).toEqualTypeOf<string>();
+expectTypeOf(color.toHTML()).toEqualTypeOf<string>();
+expectTypeOf(color.equals(4)).toEqualTypeOf<boolean>();
+expectTypeOf(color.toRGBA(5)).toEqualTypeOf<string>();
+expectTypeOf(color.mix(new Color(), 4)).toEqualTypeOf<Color>();
+expectTypeOf(color.multiply(new Color())).toEqualTypeOf<Color>();
+expectTypeOf(color.add(new Color())).toEqualTypeOf<Color>();
+expectTypeOf(color.subtract(new Color())).toEqualTypeOf<Color>();
+expectTypeOf(color.maximize(new Color())).toEqualTypeOf<Color>();
+expectTypeOf(color.applyRGB([])).toEqualTypeOf<void>();
+
+expectTypeOf(Color.mix(1, 2, 3)).toEqualTypeOf<number>();
+expectTypeOf(Color.multiplyScalar(1, 2)).toEqualTypeOf<number>();
+expectTypeOf(Color.maximize(1, 3)).toEqualTypeOf<number>();
+expectTypeOf(Color.maximizeScalar(1, 3)).toEqualTypeOf<number>();
+expectTypeOf(Color.addScalar(1, 3)).toEqualTypeOf<number>();
+expectTypeOf(Color.subtract(1, 3)).toEqualTypeOf<number>();
+expectTypeOf(Color.subtractScalar(1, 3)).toEqualTypeOf<number>();
+expectTypeOf(Color.minimize(1, 3)).toEqualTypeOf<number>();
+expectTypeOf(Color.minimizeScalar(1, 3)).toEqualTypeOf<number>();
+expectTypeOf(Color.applyRGB(1, [])).toEqualTypeOf<void>();
+
+declare const cs: foundry.utils.Color.Source;
+expectTypeOf(Color.from(cs)).toEqualTypeOf<Color>();
+
+expectTypeOf(Color.fromString("")).toEqualTypeOf<Color>();
+expectTypeOf(Color.fromRGB([1, 1, 1])).toEqualTypeOf<Color>();
+expectTypeOf(Color.fromRGBvalues(1, 1, 1)).toEqualTypeOf<Color>();
+expectTypeOf(Color.fromHSV([1, 1, 1])).toEqualTypeOf<Color>();
+expectTypeOf(Color.fromHSL([1, 1, 1])).toEqualTypeOf<Color>();
+expectTypeOf(Color.fromLinearRGB([1, 1, 1])).toEqualTypeOf<Color>();
diff --git a/tests/foundry/common/utils/event-emitter.test-d.ts b/tests/foundry/common/utils/event-emitter.test-d.ts
new file mode 100644
index 000000000..f16355ed8
--- /dev/null
+++ b/tests/foundry/common/utils/event-emitter.test-d.ts
@@ -0,0 +1,14 @@
+import { expectTypeOf } from "vitest";
+import type EventEmitterMixin from "../../../../src/foundry/common/utils/event-emitter.d.mts";
+
+declare class EventEmitter extends EventEmitterMixin(Object) {}
+declare const eventEmitter: EventEmitter;
+
+declare const listener: (event: Event) => void;
+expectTypeOf(eventEmitter.addEventListener("", listener)).toEqualTypeOf<void>();
+expectTypeOf(eventEmitter.removeEventListener("", listener)).toEqualTypeOf<void>();
+
+declare const event: Event;
+expectTypeOf(eventEmitter.dispatchEvent(event)).toEqualTypeOf<boolean>();
+
+expectTypeOf(EventEmitter.emittedEvents).toEqualTypeOf<string[]>();
diff --git a/tests/foundry/common/utils/geometry.mjs.test-d.ts b/tests/foundry/common/utils/geometry.mjs.test-d.ts
deleted file mode 100644
index a16ad4fad..000000000
--- a/tests/foundry/common/utils/geometry.mjs.test-d.ts
+++ /dev/null
@@ -1,89 +0,0 @@
-import { expectTypeOf } from "vitest";
-
-// Global export test
-expectTypeOf(orient2dFast).toEqualTypeOf(foundry.utils.orient2dFast);
-expectTypeOf(lineSegmentIntersects).toEqualTypeOf(lineSegmentIntersects);
-expectTypeOf(lineLineIntersection).toEqualTypeOf(foundry.utils.lineLineIntersection);
-expectTypeOf(lineSegmentIntersects).toEqualTypeOf(foundry.utils.lineSegmentIntersects);
-// ---
-
-const a = { x: 0, y: 0 };
-const b = new PIXI.Point(0, 0);
-const c = { x: 0, y: 0 };
-const d = new PIXI.Point(0, 0);
-
-const o = new PIXI.Circle(0, 0, 0);
-const r = new Ray(a, b);
-
-expectTypeOf(foundry.utils.orient2dFast(a, b, c)).toEqualTypeOf<number>();
-
-expectTypeOf(foundry.utils.lineSegmentIntersects(a, b, c, d)).toEqualTypeOf<boolean>();
-
-expectTypeOf(foundry.utils.lineLineIntersection(a, b, c, d)).toEqualTypeOf<foundry.utils.LineIntersection | null>();
-expectTypeOf(
-  foundry.utils.lineLineIntersection(a, b, c, d, { t1: true }),
-).toEqualTypeOf<foundry.utils.LineIntersection | null>();
-expectTypeOf(foundry.utils.lineLineIntersection(a, b, c, d, { t1: true })).toEqualTypeOf(
-  r.intersectSegment([0, 0, 0, 0]),
-);
-
-expectTypeOf(foundry.utils.lineSegmentIntersects(a, b, c, d)).toEqualTypeOf<boolean>();
-
-expectTypeOf(foundry.utils.lineCircleIntersection(a, b, c, 0).intersections).toEqualTypeOf(
-  o.segmentIntersections(a, b),
-);
-expectTypeOf(foundry.utils.lineCircleIntersection(a, b, c, 0).intersections).toEqualTypeOf(
-  foundry.utils.quadraticIntersection(a, b, c, 0),
-);
-
-// utils.polygonCentroid
-
-const points = [
-  new PIXI.Point(0, 0),
-  new PIXI.Point(1, 0),
-  new PIXI.Point(1, 2),
-  new PIXI.Point(0, 3),
-] satisfies Point[];
-
-const returnPoint = new PIXI.Point(0, 0);
-
-expectTypeOf(foundry.utils.polygonCentroid(points)).toMatchTypeOf<Point>(returnPoint);
-
-// utils.pathCircleIntersects
-
-type CircleIntersectTest = {
-  points: Parameters<typeof foundry.utils.pathCircleIntersects>[0];
-  close: Parameters<typeof foundry.utils.pathCircleIntersects>[1];
-  center: Parameters<typeof foundry.utils.pathCircleIntersects>[2];
-  radius: Parameters<typeof foundry.utils.pathCircleIntersects>[3];
-  result: ReturnType<typeof foundry.utils.pathCircleIntersects>;
-};
-
-// Testing for intersecting circle so that it actually returns what we expect
-const testIntersectingCircle: CircleIntersectTest = {
-  points: points,
-  close: true,
-  center: new PIXI.Point(0.5, 0.5),
-  radius: 1,
-  result: true,
-};
-
-expectTypeOf(
-  foundry.utils.pathCircleIntersects(
-    testIntersectingCircle.points,
-    testIntersectingCircle.close,
-    testIntersectingCircle.center,
-    testIntersectingCircle.radius,
-  ),
-).toEqualTypeOf(testIntersectingCircle.result);
-
-// utils.circleCircleIntersects
-
-expectTypeOf(foundry.utils.circleCircleIntersects).parameter(0).toBeNumber();
-expectTypeOf(foundry.utils.circleCircleIntersects).parameter(1).toBeNumber();
-expectTypeOf(foundry.utils.circleCircleIntersects).parameter(2).toBeNumber();
-expectTypeOf(foundry.utils.circleCircleIntersects).parameter(3).toBeNumber();
-expectTypeOf(foundry.utils.circleCircleIntersects).parameter(4).toBeNumber();
-expectTypeOf(foundry.utils.circleCircleIntersects).parameter(5).toBeNumber();
-
-expectTypeOf(foundry.utils.circleCircleIntersects(0, 0, 1, 0, 0, 1)).toEqualTypeOf<boolean>();
diff --git a/tests/foundry/common/utils/geometry.test-d.ts b/tests/foundry/common/utils/geometry.test-d.ts
new file mode 100644
index 000000000..6d3264c9a
--- /dev/null
+++ b/tests/foundry/common/utils/geometry.test-d.ts
@@ -0,0 +1,37 @@
+import { expectTypeOf } from "vitest";
+
+const a = { x: 0, y: 0 };
+const b = new PIXI.Point(0, 0);
+const c = { x: 0, y: 0 };
+const d = new PIXI.Point(0, 0);
+
+expectTypeOf(foundry.utils.orient2dFast(a, b, c)).toEqualTypeOf<number>();
+
+expectTypeOf(foundry.utils.lineSegmentIntersects(a, b, c, d)).toEqualTypeOf<boolean>();
+
+expectTypeOf(foundry.utils.lineLineIntersection(a, b, c, d)).toEqualTypeOf<foundry.utils.LineIntersection | null>();
+expectTypeOf(
+  foundry.utils.lineLineIntersection(a, b, c, d, { t1: true }),
+).toEqualTypeOf<foundry.utils.LineIntersection | null>();
+expectTypeOf(
+  foundry.utils.lineLineIntersection(a, b, c, d, { t1: true }),
+).toEqualTypeOf<foundry.utils.LineIntersection | null>();
+
+expectTypeOf(foundry.utils.lineCircleIntersection(a, b, c, 0)).toEqualTypeOf<foundry.utils.LineCircleIntersection>();
+
+expectTypeOf(foundry.utils.closestPointToSegment(a, b, c)).toEqualTypeOf<Canvas.Point>();
+
+expectTypeOf(foundry.utils.quadraticIntersection(a, b, c, 2, 2)).toEqualTypeOf<[Canvas.Point?, Canvas.Point?]>();
+
+const points = [
+  new PIXI.Point(0, 0),
+  new PIXI.Point(1, 0),
+  new PIXI.Point(1, 2),
+  new PIXI.Point(0, 3),
+] satisfies Canvas.Point[];
+
+expectTypeOf(foundry.utils.polygonCentroid(points)).toMatchTypeOf<Canvas.Point>();
+
+expectTypeOf(foundry.utils.pathCircleIntersects(points, true, a, 1)).toEqualTypeOf<boolean>();
+
+expectTypeOf(foundry.utils.circleCircleIntersects(1, 2, 3, 3, 2, 1)).toEqualTypeOf<boolean>();
diff --git a/tests/foundry/common/utils/helpers.mjs.test-d.ts b/tests/foundry/common/utils/helpers.test-d.ts
similarity index 86%
rename from tests/foundry/common/utils/helpers.mjs.test-d.ts
rename to tests/foundry/common/utils/helpers.test-d.ts
index 0b6ab0d29..d10c1ad67 100644
--- a/tests/foundry/common/utils/helpers.mjs.test-d.ts
+++ b/tests/foundry/common/utils/helpers.test-d.ts
@@ -1,19 +1,12 @@
 import { expectTypeOf, assertType } from "vitest";
-import type { AnyFunction, NonNullish } from "fvtt-types/utils";
-
-// Global export test
-expectTypeOf(benchmark).toEqualTypeOf(foundry.utils.benchmark);
-expectTypeOf(deepClone).toEqualTypeOf(foundry.utils.deepClone);
-expectTypeOf(duplicate).toEqualTypeOf(foundry.utils.duplicate);
-expectTypeOf(mergeObject).toEqualTypeOf(foundry.utils.mergeObject);
-// ---
-
-// benchmark
+import type { AnyConstructor, AnyFunction, NonNullish } from "fvtt-types/utils";
 
 declare function functionWithoutParameters(): void;
 declare function functionWithParameters(a: number, b: string, c?: boolean): void;
 declare function functionWithReturnTypeOtherThanVoid(): number;
 
+// benchmark
+
 expectTypeOf(foundry.utils.benchmark(functionWithoutParameters, 42)).toEqualTypeOf<Promise<void>>();
 
 // @ts-expect-error - the function takes no arguments
@@ -30,6 +23,55 @@ foundry.utils.benchmark(functionWithParameters, 42, 1, "", "unknown argument");
 
 expectTypeOf(foundry.utils.benchmark(functionWithReturnTypeOtherThanVoid, 42)).toEqualTypeOf<Promise<void>>();
 
+// threadLock
+expectTypeOf(foundry.utils.threadLock(42)).toEqualTypeOf<Promise<void>>();
+
+// debounce
+expectTypeOf(foundry.utils.debounce(functionWithoutParameters, 500)).toEqualTypeOf<() => void>();
+expectTypeOf(foundry.utils.debounce(functionWithParameters, 500)).toEqualTypeOf<
+  (a: number, b: string, c?: boolean) => void
+>();
+
+// throttle
+expectTypeOf(foundry.utils.throttle(functionWithoutParameters, 500)).toEqualTypeOf<() => void>();
+expectTypeOf(foundry.utils.throttle(functionWithParameters, 500)).toEqualTypeOf<
+  (a: number, b: string, c?: boolean) => void
+>();
+expectTypeOf(foundry.utils.throttle(() => {}, 1)).toBeFunction();
+
+expectTypeOf(
+  foundry.utils.throttle((a: number) => {
+    console.log(a);
+  }, 1),
+).toMatchTypeOf<(a: number) => void>();
+
+expectTypeOf(
+  foundry.utils.throttle((a: number, b: string) => {
+    console.log(a, b);
+  }, 1),
+).toMatchTypeOf<(a: number, b: string) => void>();
+
+expectTypeOf(
+  foundry.utils.throttle((a: number, b: string, c: boolean) => {
+    console.log(a, b, c);
+  }, 1),
+).toMatchTypeOf<(a: number, b: string, c: boolean) => void>();
+
+expectTypeOf(
+  foundry.utils.throttle((a: number, b: string, c: boolean, d: symbol) => {
+    console.log(a, b, c, d);
+  }, 1),
+).toMatchTypeOf<(a: number, b: string, c: boolean, d: symbol) => void>();
+
+expectTypeOf(
+  foundry.utils.throttle((a: number, b: string, c: boolean, d: symbol, e: bigint) => {
+    console.log(a, b, c, d, e);
+  }, 1),
+).toMatchTypeOf<(a: number, b: string, c: boolean, d: symbol, e: bigint) => void>();
+
+// debouncedReoload
+expectTypeOf(foundry.utils.debouncedReload).toEqualTypeOf<() => void>();
+
 // deepClone
 
 const complexObject = {
@@ -73,10 +115,9 @@ expectTypeOf(foundry.utils.deepClone("abc" as string, { strict: true as boolean
 expectTypeOf(foundry.utils.diffObject({ a: 1 }, { a: 1 })).toEqualTypeOf<object>();
 expectTypeOf(foundry.utils.diffObject({ a: 1 }, { a: 7, b: 2 })).toEqualTypeOf<object>();
 
-// getDefiningClass
+// objectsEqual
 
-expectTypeOf(foundry.utils.getDefiningClass).parameter(0).toBeObject();
-expectTypeOf(foundry.utils.getDefiningClass).parameter(1).toBeString();
+expectTypeOf(foundry.utils.objectsEqual({ a: 1 }, { a: 1 })).toEqualTypeOf<boolean>();
 
 // duplicate
 
@@ -240,12 +281,67 @@ expectTypeOf(
   foundry.utils.isSubclass(ClassWithConstructorParameters, ClassWithNoConstructorParameters),
 ).toEqualTypeOf<boolean>();
 
+// getDefiningClass
+expectTypeOf(foundry.utils.getDefiningClass(foundry.documents.BaseActor, "name")).toEqualTypeOf<AnyConstructor>();
+
+// encodeURL
+expectTypeOf(foundry.utils.encodeURL("")).toEqualTypeOf<string>();
+
+// expandObject
+expectTypeOf(foundry.utils.expandObject({})).toEqualTypeOf<object>();
+
+// filterObject
+expectTypeOf(foundry.utils.filterObject({}, {})).toEqualTypeOf<object>();
+
+// flattenObject
+expectTypeOf(foundry.utils.flattenObject({})).toEqualTypeOf<object>();
+
+// getParentClasses
+expectTypeOf(foundry.utils.getParentClasses(foundry.documents.BaseActor)).toEqualTypeOf<AnyConstructor[]>();
+
+// getRoute
+expectTypeOf(foundry.utils.getRoute("")).toEqualTypeOf<string>();
+
+// getType
+expectTypeOf(foundry.utils.getType("")).toEqualTypeOf<
+  | "Array"
+  | "Error"
+  | "HTMLElement"
+  | "Map"
+  | "Object"
+  | "Promise"
+  | "Set"
+  | "bigint"
+  | "boolean"
+  | "function"
+  | "null"
+  | "number"
+  | "string"
+  | "symbol"
+  | "undefined"
+>();
+
+// hasProperty
+expectTypeOf(foundry.utils.hasProperty({}, "")).toEqualTypeOf<boolean>();
+
+// getProperty
+expectTypeOf(foundry.utils.getProperty({}, "")).toEqualTypeOf<any>();
+
+// setProperty
+expectTypeOf(foundry.utils.setProperty({}, "", 4)).toEqualTypeOf<boolean>();
+
 // invertObject
 expectTypeOf(foundry.utils.invertObject({ a: 1, b: "foo" } as const)).toEqualTypeOf<{
   readonly 1: "a";
   readonly foo: "b";
 }>();
 
+// isNewerVersion
+expectTypeOf(foundry.utils.isNewerVersion(4, "2.3")).toEqualTypeOf<boolean>();
+
+// isEmpty
+expectTypeOf(foundry.utils.isEmpty(4)).toEqualTypeOf<boolean>();
+
 // mergeObject: assertType is used here because of https://github.com/SamVerschueren/tsd/issues/67
 // mergeObject (1): tests from the docs
 assertType<{ k1: string }>(foundry.utils.mergeObject({ k1: "v1" }, { k2: "v2" }, { insertKeys: false }));
@@ -445,36 +541,24 @@ foundry.utils.mergeObject(1, 2);
 // @ts-expect-error - A string isn't a valid object to merge.
 foundry.utils.mergeObject("foo", "bar");
 
-// Additions v12
-//   - throttle
-expectTypeOf(foundry.utils.throttle(() => {}, 1)).toBeFunction();
+// parseS3URL
+expectTypeOf(foundry.utils.parseS3URL("")).toEqualTypeOf<{ bucket: string | null; keyPrefix: string }>();
 
-expectTypeOf(
-  foundry.utils.throttle((a: number) => {
-    console.log(a);
-  }, 1),
-).toMatchTypeOf<(a: number) => void>();
+// randomID
+expectTypeOf(foundry.utils.randomID(16)).toEqualTypeOf<string>();
+expectTypeOf(foundry.utils.randomID()).toEqualTypeOf<string>();
 
-expectTypeOf(
-  foundry.utils.throttle((a: number, b: string) => {
-    console.log(a, b);
-  }, 1),
-).toMatchTypeOf<(a: number, b: string) => void>();
+// timeSince
+expectTypeOf(foundry.utils.timeSince(new Date())).toEqualTypeOf<string>();
+expectTypeOf(foundry.utils.timeSince("")).toEqualTypeOf<string>();
 
-expectTypeOf(
-  foundry.utils.throttle((a: number, b: string, c: boolean) => {
-    console.log(a, b, c);
-  }, 1),
-).toMatchTypeOf<(a: number, b: string, c: boolean) => void>();
+// formatFileSize
+expectTypeOf(foundry.utils.formatFileSize(4, { base: 2 })).toEqualTypeOf<string>();
+expectTypeOf(foundry.utils.formatFileSize(4)).toEqualTypeOf<string>();
 
-expectTypeOf(
-  foundry.utils.throttle((a: number, b: string, c: boolean, d: symbol) => {
-    console.log(a, b, c, d);
-  }, 1),
-).toMatchTypeOf<(a: number, b: string, c: boolean, d: symbol) => void>();
+// @ts-expect-error: base must be 2 or 10
+expectTypeOf(foundry.utils.formatFileSize(4, { base: 6 })).toEqualTypeOf<string>();
 
-expectTypeOf(
-  foundry.utils.throttle((a: number, b: string, c: boolean, d: symbol, e: bigint) => {
-    console.log(a, b, c, d, e);
-  }, 1),
-).toMatchTypeOf<(a: number, b: string, c: boolean, d: symbol, e: bigint) => void>();
+// parseUuid
+expectTypeOf(foundry.utils.parseUuid("", {})).toEqualTypeOf<foundry.utils.ResolvedUUID>();
+expectTypeOf(foundry.utils.parseUuid("")).toEqualTypeOf<foundry.utils.ResolvedUUID>();
diff --git a/tests/foundry/common/utils/http.mjs.test-d.ts b/tests/foundry/common/utils/http.test-d.ts
similarity index 66%
rename from tests/foundry/common/utils/http.mjs.test-d.ts
rename to tests/foundry/common/utils/http.test-d.ts
index eab56bcbd..1d7ef7ae2 100644
--- a/tests/foundry/common/utils/http.mjs.test-d.ts
+++ b/tests/foundry/common/utils/http.test-d.ts
@@ -1,8 +1,6 @@
 import { expectTypeOf } from "vitest";
 
-// Global export test
-expectTypeOf(fetchWithTimeout).toEqualTypeOf(foundry.utils.fetchWithTimeout);
-// ---
-
 expectTypeOf(foundry.utils.fetchWithTimeout("/")).toEqualTypeOf<Promise<Response>>();
 expectTypeOf(foundry.utils.fetchJsonWithTimeout("/")).toEqualTypeOf<Promise<unknown>>();
+
+expectTypeOf(new foundry.utils.HttpError("", 4, "")).toEqualTypeOf<foundry.utils.HttpError>();
diff --git a/tests/foundry/common/utils/iterable-weak-map.test-d.ts b/tests/foundry/common/utils/iterable-weak-map.test-d.ts
index 038a58661..282e46ea7 100644
--- a/tests/foundry/common/utils/iterable-weak-map.test-d.ts
+++ b/tests/foundry/common/utils/iterable-weak-map.test-d.ts
@@ -1,12 +1,13 @@
 import { expectTypeOf } from "vitest";
 
-const m = new IterableWeakMap<{ x: number }, { y: string }>();
+const m = new foundry.utils.IterableWeakMap<{ x: number }, { y: string }>();
 
+expectTypeOf(m.delete({ x: 1 })).toEqualTypeOf<boolean>();
 expectTypeOf(m.get({ x: 1 })).toEqualTypeOf<{ y: string } | undefined>();
 
 expectTypeOf(m.set({ x: 1 }, { y: "2" })).toEqualTypeOf<IterableWeakMap<{ x: number }, { y: string }>>();
 
-// expectTypeOf(m.entries()).toEqualTypeOf<Generator<[{ x: number }, { y: string }], void, never>>();
+expectTypeOf(m.entries()).toEqualTypeOf<Generator<[{ x: number }, { y: string }], void, never>>();
 expectTypeOf(m.keys()).toEqualTypeOf<Generator<{ x: number }, void, never>>();
 expectTypeOf(m.values()).toEqualTypeOf<Generator<{ y: string }, void, never>>();
 
diff --git a/tests/foundry/common/utils/iterable-weak-set.test-d.ts b/tests/foundry/common/utils/iterable-weak-set.test-d.ts
index 4840c5f88..94bd8d2c3 100644
--- a/tests/foundry/common/utils/iterable-weak-set.test-d.ts
+++ b/tests/foundry/common/utils/iterable-weak-set.test-d.ts
@@ -1,8 +1,10 @@
 import { expectTypeOf } from "vitest";
 
-const m = new IterableWeakSet<{ x: number }>();
+const m = new foundry.utils.IterableWeakSet<{ x: number }>();
 
 expectTypeOf(m.add({ x: 1 })).toEqualTypeOf<IterableWeakSet<{ x: number }>>();
+expectTypeOf(m.delete({ x: 1 })).toEqualTypeOf<boolean>();
+expectTypeOf(m.has({ x: 1 })).toEqualTypeOf<boolean>();
 
 expectTypeOf(m.values()).toEqualTypeOf<Generator<{ x: number }, void, never>>();
 
diff --git a/tests/foundry/common/utils/logging.mjs.test-d.ts b/tests/foundry/common/utils/logging.test-d.ts
similarity index 100%
rename from tests/foundry/common/utils/logging.mjs.test-d.ts
rename to tests/foundry/common/utils/logging.test-d.ts
diff --git a/tests/foundry/common/utils/semaphore.mjs.test-d.ts b/tests/foundry/common/utils/semaphore.test-d.ts
similarity index 73%
rename from tests/foundry/common/utils/semaphore.mjs.test-d.ts
rename to tests/foundry/common/utils/semaphore.test-d.ts
index bfeb1304e..195e7951c 100644
--- a/tests/foundry/common/utils/semaphore.mjs.test-d.ts
+++ b/tests/foundry/common/utils/semaphore.test-d.ts
@@ -10,3 +10,7 @@ lock.add(async (s: string) => !s);
 
 // @ts-expect-error - The callback doesn't need any arguments.
 lock.add(async () => false, "");
+
+expectTypeOf(lock.remaining).toEqualTypeOf<number>();
+expectTypeOf(lock.active).toEqualTypeOf<number>();
+expectTypeOf(lock.clear()).toEqualTypeOf<void>();