Last active
April 18, 2023 20:02
-
-
Save tvler/413cdcd11f7c12bc392eab6149cc19b2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* A function to create namespaced enums, where the return type | |
* is a literal reflection of the returned enum value itself. | |
* | |
* Ex: | |
* createNamespacedEnum({ | |
* setA: ['a', 'b'], | |
* setB: ['a', 'b'], | |
* }); | |
* | |
* // Generated object and type: | |
* { | |
* setA: { a: 'setA.a', b: 'setA.b' } | |
* setB: { a: 'setB.a', b: 'setB.b' } | |
* } | |
*/ | |
export function createNamespacedEnum< | |
Namespace extends string, | |
EnumKey extends string, | |
EnumKeys extends Array<EnumKey>, | |
Input extends Record<Namespace, [...EnumKeys]> | |
>( | |
input: Input, | |
): { | |
[namespace in StringKeys<Input>]: { | |
[enumKey in ArrayElementType<Input[namespace]>]: `${namespace}.${enumKey}`; | |
}; | |
} { | |
type EnumValue = `${Namespace}.${EnumKey}`; | |
type PartialNamespacedEnum = Record<Namespace, Record<EnumKey, EnumValue>>; | |
const partialNamespacedEnums: Array<PartialNamespacedEnum> = (Object.entries(input) as Array< | |
[key: Namespace, value: EnumKeys] | |
>).map(([namespace, enumKeys]) => { | |
const enumObj = {} as Record<EnumKey, EnumValue>; | |
for (const enumKey of enumKeys) { | |
const enumValue: EnumValue = `${namespace}.${enumKey}`; | |
enumObj[enumKey] = enumValue; | |
} | |
return { [namespace]: enumObj } as PartialNamespacedEnum; | |
}); | |
const namespacedEnum = Object.assign({}, ...partialNamespacedEnums); | |
return namespacedEnum; | |
} | |
// Auxiliary types: | |
/** | |
* Extracts the keys of a type, and casts them all to be strings | |
* (a key can naturally be a string, number, or symbol). | |
*/ | |
export type StringKeys<T extends { [k: string]: any }> = T extends infer G | |
? `${string & keyof G}` | |
: never; | |
/** | |
* Gets all the element types of an array and returns them all as a union | |
*/ | |
type ArrayElementType<Arr> = Arr extends Array<infer ElementType> ? ElementType : never; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type GlobalParamList = { | |
// Opendoor's global ParamList | |
}; | |
/** | |
* The ParamList for a specific navigator in our app. | |
* Defaults to including every navigator. | |
*/ | |
export type ParamList< | |
NavigatorName extends keyof typeof Routes = keyof typeof Routes, | |
RouteNamesWithParams extends keyof GlobalParamList = Extract< | |
RouteNames<NavigatorName>, | |
keyof GlobalParamList | |
> | |
> = Pick<GlobalParamList, RouteNamesWithParams> & | |
Omit< | |
{ | |
[key in RouteNames<NavigatorName>]: undefined; | |
}, | |
RouteNamesWithParams | |
>; | |
// Auxiliary types: | |
export type RouteNames< | |
NavigatorName extends keyof typeof Routes = keyof typeof Routes | |
> = LeafStrings<typeof Routes[NavigatorName]>; | |
/** | |
* A type that returns a union of all of an object's string values | |
* of an arbitrary depth. | |
* | |
* Ex: | |
* type Obj = { | |
* a: { key1: 'value1'; key2: 'value2' }; | |
* b: { key3: 'value3'; key4: 'value4' }; | |
* }; | |
* | |
* // "value1" | "value2" | "value3" | "value4" | |
* export type Values = LeafStrings<Obj>; | |
*/ | |
export type LeafStrings<T extends Record<string, any> | string> = T extends string | |
? T | |
: LeafStrings<T[keyof T]>; | |
/** | |
* Extracts the keys of a type, and casts them all to be strings | |
* (a key can naturally be a string, number, or symbol). | |
*/ | |
export type StringKeys<T extends { [k: string]: any }> = T extends infer G | |
? `${string & keyof G}` | |
: never; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment