Last active
October 3, 2023 04:33
-
-
Save DuCanhGH/c7788ef93bb07070d62ffb928693741f to your computer and use it in GitHub Desktop.
utils_types.ts
This file contains hidden or 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
/** | |
* Make certain fields in a object type required | |
* | |
* @example | |
* interface A { | |
* a?: string; | |
* b?: string; | |
* c?: string; | |
* } | |
* type B = RequireFields<A, "b" | "c">; | |
* const b: B = { | |
* b: "hehe", | |
* c: "hehe", | |
* }; //valid | |
* const b: B = { a: "hehe" }; //invalid | |
* const c: B = { a: "hehe", b: "hehe" }; //invalid | |
*/ | |
type RequireFields<T, U extends keyof T> = T & Required<Pick<T, U>>; | |
/** | |
* Make certain fields in a object type optional | |
* | |
* @example | |
* interface A { | |
* a: string; | |
* b: string; | |
* c: string; | |
* } | |
* type B = Optional<A, "b" | "c">; | |
* const b: B = { a: "hehe" }; //valid | |
* const b: B = {}; //invalid | |
*/ | |
type Optional<T, U extends keyof T> = Omit<T, U> & Partial<Pick<T, U>>; | |
/** | |
* Add prefix to a string | |
* | |
* @example | |
* type A = WithPrefix<"hehe">; | |
* const a: A = "heheboy"; | |
* const b: A = "boy"; // invalid | |
*/ | |
type WithPrefix<T extends string> = `${T}${string}`; | |
/** | |
* Get all possible paths to children in an object | |
* | |
* @example | |
* const a = { | |
* a: { | |
* b: { | |
* c: "hehe", | |
* }, | |
* }, | |
* }; | |
* type A = NestedKeyOf<typeof a>; | |
* // type A is "a" | "a.b" | "a.b.c" | |
*/ | |
type NestedKeyOf<T> = T extends Record<string, unknown> | |
? { | |
[Key in Extract<keyof T, string>]: T[Key] extends Array<any> | |
? `${Key}` | |
: T[Key] extends Record<string, unknown> | |
? `${Key}` | `${Key}.${NestedKeyOf<T[Key]>}` | |
: `${Key}`; | |
}[Extract<keyof T, string>] | |
: undefined; | |
/** | |
* Get all types of children in an object | |
* | |
* @example | |
* const a = { | |
* a: { | |
* b: { | |
* c: "hehe", | |
* }, | |
* }, | |
* }; | |
* type A = NestedKeyTypes<typeof a, keyof typeof a>; | |
* // type A is string | { c: string; } | { b: { c: string; }; } | |
*/ | |
type NestedKeyTypes<T, K extends keyof T> = T extends Record<string, unknown> | |
? T[K] extends Array<T[K][keyof T[K]]> | |
? T[K] | |
: T[K] extends object | |
? NestedKeyTypes<T[K], keyof T[K]> | T[K] | |
: T[K] | |
: undefined; | |
/** | |
* Split a string type into an array of strings | |
* | |
* @example | |
* type A = Split<"1.2.3.4", ".">; | |
* // type A is ["1", "2", "3", "4"] | |
* const a: A = ["1", "2", "3", "4"]; //this array only allows string "1", "2", "3", "4", nothing else | |
* type B = Partial<A>; | |
* // type B is [("1" | undefined)?, ("2" | undefined)?, ("3" | undefined)?, ("4" | undefined)?] | |
* const b: B = ["1", "2"]; //this array only allows string "1", "2", "3", "4", nothing else, but you can leave some out | |
*/ | |
type Split<S extends string, D extends string> = string extends S | |
? string[] | |
: S extends "" | |
? [] | |
: S extends `${infer T}${D}${infer U}` | |
? [T, ...Split<U, D>] | |
: [S]; | |
/** | |
* Get type of child at path S in an object | |
* | |
* @example | |
* const a = { | |
* a: { | |
* b: { | |
* c: "hehe", | |
* }, | |
* }, | |
* }; | |
* type A = GetValueAtPath<typeof a, "a.b.c">; | |
* // type A is string | |
* type B = GetValueAtPath<typeof a, "a.b">; | |
* // type B is { c: string; } | |
*/ | |
type GetValueAtPath<T, S extends NestedKeyOf<T> | undefined> = T extends Record<string, any> | |
? S extends `${infer V}.${infer U}` | |
? T[V] extends Record<string, any> | |
? U extends NestedKeyOf<T[V]> | |
? GetValueAtPath<T[V], U> | |
: undefined | |
: T[V] | |
: S extends string | |
? T[S] | |
: undefined | |
: undefined; | |
export type { | |
GetValueAtPath, | |
NestedKeyOf, | |
NestedKeyTypes, | |
Optional, | |
RequireFields, | |
Split, | |
WithPrefix, | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment