@@ -74,22 +74,72 @@ export declare function ButterTupleEnum<const T extends readonly string[]>(tuple
7474 * colorsEnum.keys // ['green']
7575 * ```
7676 *
77- * @template TEnum The object type containing enum entries
78- * @returns The keyed enum object with helper methods
77+ * @template KeyName - The name of the property to hoist the key into. Defaults to `"key"`.
78+ * @template T - The original enum-like object whose keys should not conflict with `keyName` in inner objects.
79+ * @template TTuple - The tuple of values derived from `T` that will represent the enum values.
80+ * @template TResult - The final result tuple validated against the keys of `T`.
81+ *
82+ * @param {T } enumObject - The original object representing the enum-like mapping.
83+ * @param {Object } options - Configuration options.
84+ * @param {KeyName } [options.keyName="key"] - The name of the key to inject into each value.
85+ * @param {(enumObject: Readonly<HoistKeyToInner<T, KeyName>>) => TResult } options.tupleFactory - A factory function
86+ * that takes the modified enum object with keys hoisted and returns a tuple. It must include all keys from `enumObject`.
87+ *
88+ * This is required because typescript cannot convert from a union to a tuple with
89+ * * Guaranteed order
90+ * * Better performance than O(n^2)
91+ * See https://stackoverflow.com/questions/55127004/how-to-transform-union-type-to-tuple-type
92+ *
93+ * So, we have to provide a tuple factory. It constrains the tuple to make sure you're not missing any values.
94+ * Making our typescript compiler happy.
95+ *
96+ * @returns {void } This function does not return anything directly, but can be used to enforce compile-time constraints
97+ * and build strongly typed enums using TypeScript's type system.
98+ *
99+ * @throws {TypeError } If any object in `enumObject` already contains the `keyName` property, it will result in a type error.
100+ * @throws {Error } If the `tupleFactory` does not return a tuple that includes all keys, a compile-time type error will occur.
79101 */
80102export declare function ButterKeyedEnum < KeyName extends string = "key" , const T extends {
81103 [ K in keyof T ] : KeyName extends keyof T [ K ] ? never : Record < string , any > ;
82104} = {
83105 [ key : string ] : any ;
84- } > ( enumObject : T , options ? : {
106+ } , TTuple extends [ T [ keyof T ] , ... T [ keyof T ] [ ] ] = [ T [ keyof T ] , ... T [ keyof T ] [ ] ] , TResult extends [ T [ keyof T ] , ... T [ keyof T ] [ ] ] = TTuple > ( enumObject : T , options : {
85107 keyName ?: KeyName ;
108+ /**
109+ * A factory function that takes the modified enum object with keys hoisted and returns a tuple.
110+ * It must include all keys from `enumObject`.
111+ *
112+ * @param enumObject The enum object with keys hoisted into each value
113+ * @returns A tuple of values from the enum object
114+ *
115+ * This is required because typescript cannot convert from a union to a tuple with
116+ * * Guaranteed order
117+ * * Better performance than O(n^2)
118+ * See https://stackoverflow.com/questions/55127004/how-to-transform-union-type-to-tuple-type
119+ *
120+ * So, we have to provide a tuple factory. It constrains the tuple to make sure you're not missing any values.
121+ * Making our typescript compiler happy.
122+ */
123+ tupleFactory : ( enumObject : Readonly < HoistKeyToInner < T , KeyName > > ) => IsTypeEqual < TResult [ number ] [ KeyName ] , keyof T > extends true ? TResult : {
124+ error : "You must include all keys in the tuple" ;
125+ value : never ;
126+ } ;
86127} ) : {
87128 /**
88129 * The enum object
89130 *
90131 * @type {Readonly<TEnum> } The enum object with keys hoisted into each value
91132 */
92133 readonly enum : Readonly < HoistKeyToInner < T , KeyName > > ;
134+ /**
135+ * An ordered array of enum values as specified by the tupleFactory function
136+ *
137+ * @type {TTuple } The tuple of enum values in the order defined by tupleFactory
138+ */
139+ readonly tuple : IsTypeEqual < TResult [ number ] [ KeyName ] , keyof T > extends true ? TResult : {
140+ error : "You must include all keys in the tuple" ;
141+ value : never ;
142+ } ;
93143 /**
94144 * Gets a value by key
95145 *
@@ -137,4 +187,8 @@ type HoistKeyToInner<T, KeyName extends string = "key"> = {
137187 [ P in keyof O | KeyName ] : P extends keyof O ? O [ P ] : K ;
138188 } : never ;
139189} ;
190+ /**
191+ * Utility type that checks if two types are equal
192+ */
193+ type IsTypeEqual < A , B > = ( < T > ( ) => T extends A ? 1 : 2 ) extends ( < T > ( ) => T extends B ? 1 : 2 ) ? true : false ;
140194export { } ;
0 commit comments