Fiexd up tests

This commit is contained in:
Bertie690 2025-06-23 22:50:21 -04:00
parent 47e9dabb07
commit 489295f2c0
3 changed files with 36 additions and 17 deletions

View File

@ -2,8 +2,10 @@
* A collection of custom utility types that aid in type checking and ensuring strict type conformity * A collection of custom utility types that aid in type checking and ensuring strict type conformity
*/ */
// biome-ignore lint/correctness/noUnusedImports: Used in a tsdoc comment // biome-ignore-start lint/correctness/noUnusedImports: Used in a tsdoc comment
import type { EnumValues } from "#app/@types/enum-types";
import type { AbAttr } from "./ability-types"; import type { AbAttr } from "./ability-types";
// biome-ignore-end lint/correctness/noUnusedImports: Used in a tsdoc comment
/** /**
* Exactly matches the type of the argument, preventing adding additional properties. * Exactly matches the type of the argument, preventing adding additional properties.
@ -11,7 +13,7 @@ import type { AbAttr } from "./ability-types";
* Should never be used with `extends`, as this will nullify the exactness of the type. * Should never be used with `extends`, as this will nullify the exactness of the type.
* *
* As an example, used to ensure that the parameters of {@linkcode AbAttr.canApply} and {@linkcode AbAttr.getTriggerMessage} are compatible with * As an example, used to ensure that the parameters of {@linkcode AbAttr.canApply} and {@linkcode AbAttr.getTriggerMessage} are compatible with
* the type of the apply method * the type of its {@linkcode AbAttr.apply | apply} method.
* *
* @typeParam T - The type to match exactly * @typeParam T - The type to match exactly
*/ */
@ -26,9 +28,18 @@ export type Exact<T> = {
export type Closed<X> = X; export type Closed<X> = X;
/** /**
* Remove `readonly` from all properties of the provided type * Remove `readonly` from all properties of the provided type.
* @typeParam T - The type to make mutable * @typeParam T - The type to make mutable.
*/ */
export type Mutable<T> = { export type Mutable<T> = {
-readonly [P in keyof T]: T[P]; -readonly [P in keyof T]: T[P];
}; };
/**
* Type helper to obtain the keys associated with a given value inside a `const object`.
* @typeParam O - The type of the object
* @typeParam V - The type of one of O's values
*/
export type InferKeys<O extends Record<keyof any, unknown>, V extends EnumValues<O>> = {
[K in keyof O]: O[K] extends V ? K : never;
}[keyof O];

View File

@ -1,9 +1,10 @@
import type { EnumOrObject, EnumValues, TSNumericEnum, NormalEnum } from "#app/@types/enum-types"; import type { EnumOrObject, EnumValues, TSNumericEnum, NormalEnum } from "#app/@types/enum-types";
import type { InferKeys } from "#app/@types/type-helpers";
/** /**
* Return the string keys of an Enum object, excluding reverse-mapped numbers. * Return the string keys of an Enum object, excluding reverse-mapped numbers.
* @param enumType - The numeric enum to retrieve keys for. * @param enumType - The numeric enum to retrieve keys for
* @returns An ordered array of all of `enumType`'s string keys. * @returns An ordered array of all of `enumType`'s string keys
* @example * @example
* enum fruit { * enum fruit {
* apple = 1, * apple = 1,
@ -23,8 +24,8 @@ export function getEnumKeys<E extends EnumOrObject>(enumType: TSNumericEnum<E>):
/** /**
* Return the numeric values of a numeric Enum object, excluding reverse-mapped strings. * Return the numeric values of a numeric Enum object, excluding reverse-mapped strings.
* @param enumType - The enum object to retrieve keys for. * @param enumType - The enum object to retrieve keys for
* @returns An ordered array of all of `enumType`'s number values. * @returns An ordered array of all of `enumType`'s number values
* @example * @example
* enum fruit { * enum fruit {
* apple = 1, * apple = 1,
@ -46,9 +47,9 @@ export function getEnumValues<E extends EnumOrObject>(enumType: TSNumericEnum<E>
/** /**
* Return the name of the key that matches the given Enum value. * Return the name of the key that matches the given Enum value.
* Can be used to emulate Typescript reverse mapping for `const object`s or string enums. * Can be used to emulate Typescript reverse mapping for `const object`s or string enums.
* @param object - The {@linkcode NormalEnum} to check. * @param object - The {@linkcode NormalEnum} to check
* @param val - The value to get the key of. * @param val - The value to get the key of
* @returns The name of the key with the specified value. * @returns The name of the key with the specified value
* @example * @example
* const thing = { * const thing = {
* one: 1, * one: 1,
@ -57,15 +58,16 @@ export function getEnumValues<E extends EnumOrObject>(enumType: TSNumericEnum<E>
* console.log(enumValueToKey(thing, 2)); // output: "two" * console.log(enumValueToKey(thing, 2)); // output: "two"
* @throws Error if an invalid enum value is passed to the function * @throws Error if an invalid enum value is passed to the function
* @remarks * @remarks
* If multiple keys map to the same value, the first one (in insertion order) will be retrieved. * If multiple keys map to the same value, the first one (in insertion order) will be retrieved,
* but the return type will be the union of ALL their corresponding keys.
*/ */
export function enumValueToKey<T extends EnumOrObject, V extends EnumValues<T>>( export function enumValueToKey<T extends EnumOrObject, V extends EnumValues<T>>(
object: NormalEnum<T>, object: NormalEnum<T>,
val: V, val: V,
): keyof T { ): InferKeys<T, V> {
for (const [key, value] of Object.entries(object)) { for (const [key, value] of Object.entries(object)) {
if (val === value) { if (val === value) {
return key; return key as InferKeys<T, V>;
} }
} }
throw new Error(`Invalid value passed to \`enumValueToKey\`! Value: ${val}`); throw new Error(`Invalid value passed to \`enumValueToKey\`! Value: ${val}`);

View File

@ -1,7 +1,7 @@
import type { EnumOrObject, EnumValues, TSNumericEnum, NormalEnum } from "#app/@types/enum-types"; import type { EnumOrObject, EnumValues, TSNumericEnum, NormalEnum } from "#app/@types/enum-types";
import type { getEnumKeys, getEnumValues } from "#app/utils/enums"; import type { getEnumKeys, getEnumValues } from "#app/utils/enums";
import { enumValueToKey } from "#app/utils/enums"; import type { enumValueToKey } from "#app/utils/enums";
import { expectTypeOf, describe, it } from "vitest"; import { expectTypeOf, describe, it } from "vitest";
@ -94,8 +94,14 @@ describe("Enum Functions", () => {
describe("enumValueToKey", () => { describe("enumValueToKey", () => {
it("should retrieve values for a given key", () => { it("should retrieve values for a given key", () => {
// @ts-expect-error oopsie expectTypeOf<
expectTypeOf(enumValueToKey(testEnumString, testEnumString.testS1)).toEqualTypeOf<"testS1">(); typeof enumValueToKey<typeof testEnumString, testEnumString.testS1>
>().returns.toEqualTypeOf<"testS1">();
expectTypeOf<typeof enumValueToKey<typeof testEnumString, testEnumString>>().returns.toEqualTypeOf<
"testS1" | "testS2"
>();
expectTypeOf<typeof enumValueToKey<typeof testObjNum, 1>>().returns.toEqualTypeOf<"testON1">();
expectTypeOf<typeof enumValueToKey<typeof testObjNum, 1 | 2>>().returns.toEqualTypeOf<"testON1" | "testON2">();
}); });
}); });
}); });