typescript-generic-types
Version:
A comprehensive collection of useful TypeScript generic types and utility types to enhance type-safety and developer experience. Includes array, promise, object manipulation, and advanced conditional types.
247 lines (197 loc) • 7.33 kB
TypeScript
type ObjectId = string
type Env = 'test' | 'development' | 'production' | 'preprod' | 'build' | 'ci'
type MaybeArray<T> = T | T[]
type MaybePromise<T> = T | Promise<T>
type HasKeys<T> = keyof T extends never ? false : true
type FunctionGeneric = (...params: any[]) => any
type ObjectGeneric = { [k: string]: any }
type ObjectWithNoFn = { [name: string]: NotFunction<any> }
// eslint-disable-next-line @typescript-eslint/ban-types
type NotFunction<T> = T extends Function ? never : T
type AsType<T, Type> = T extends Type ? T : Type
type AsString<T> = AsType<T, string>
type Complete<T> = {
[P in keyof Required<T>]: T[P];
}
type CountryCodeIso = `${Letters}${Letters}`
type TranslationObj = { [countryIsoCode in CountryCodeIso]?: string }
type Override<T1, T2> = Omit<T1, keyof T2> & T2
type RecursivePartial<T> = {
[P in keyof T]?: T[P] extends (infer U)[]
? RecursivePartial<U>[]
: T[P] extends object
? RecursivePartial<T[P]>
: T[P];
}
type Letters = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z'
type SimpleNumbers = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11
type ArrayOneOrMore<T> = { 0: T } & Array<T>
type RecursiveObjValueType<T, Type> = {
[K in keyof T]?: T[K] extends object
? Type | RecursiveObjValueType<T[K], Type>
: Type;
}
type TypeObjectValues<Obj extends Record<string, any>, Type> = {
[K in keyof Obj]: Type;
}
/** Return true | false whenever an object has a property of type U */
type HasPropertyOfType<Objectt extends Record<string, any>, ExpectedType> = {
[K in keyof Objectt]: Objectt[K] extends ExpectedType ? true : never;
}[keyof Objectt] extends never
? false
: true
// https://stackoverflow.com/questions/49580725/is-it-possible-to-restrict-typescript-object-to-contain-only-properties-defined
type NoExtraProperties<T, U extends T = T> = U &
MakeObjKeysAsNever<Exclude<keyof U, keyof T>>
type MakeObjKeysAsNever<K extends keyof any> = { [P in K]: never }
type RemoveTypeFromTuple<T, TypeToRemove> = T extends []
? []
: T extends TypeToRemove
? []
: T extends [infer A, ...infer R]
? [
...RemoveTypeFromTuple<A, TypeToRemove>,
...RemoveTypeFromTuple<R, TypeToRemove>
]
: [T]
type GetTypeKeyFromObject<ObjType, Type> = {
[P in keyof ObjType]: ObjType[P] extends Type ? never : P;
}[keyof ObjType]
/** Remove object key/values that are of a certain type */
type RemoveTypeFromObj<ObjType, Type> = Pick<
ObjType,
GetTypeKeyFromObject<ObjType, Type>
>
/** Get keys where the key type (number, string, Symbol...) is of Type */
type GetObjectKeysThatAreOfType<ObjType, Type> = {
[P in keyof ObjType]: P extends Type ? P : never
}[keyof ObjType]
/** Remove Symbol and number from Object type */
type ForceStringKeyObject<Obj extends Record<any, any>> = Pick<
Obj,
GetObjectKeysThatAreOfType<Obj, string>
>
/** Get all indices of an array as a type. Eg: 0 | 1 | 2... */
type Indices<T extends readonly any[]> = Exclude<
Partial<T>['length'],
T['length']
>
/** Remove Readonly Modifier */
type Writeable<T> = { -readonly [P in keyof T]: T[P] }
/** Remove Readonly Modifier Recursively */
type DeepWriteable<T> = { -readonly [P in keyof T]: DeepWriteable<T[P]> }
/** used to type generic function without having to do (...params: any) => any */
type GenericFunction = (...params: any[]) => any
/** used like IsObject<ReturnType> extends true ? .... */
type IsObject<T> = T extends Record<string, any>
? T extends GenericFunction ? false
: T extends any[] | readonly any[] ? false
: true
: false
type ReadonlyDeep<T> = {
readonly [P in keyof T]: IsObject<T[P]> extends true
? ReadonlyDeep<T[P]>
: T[P];
}
/** Equivalent of { myPropA: string, otherProp?: never } | { myPropA?: never, otherProp: string }. This would be written Exclusive<{ myPropA: string }, { otherProp: string }> */
type Exclusive<
A extends Record<string, any>,
B extends Record<string, any>,
C extends Record<string, any> = {},
D extends Record<string, any> = {},
E extends Record<string, any> = {}
> =
| ({
[P in Exclude<keyof A | keyof C | keyof D | keyof E, keyof B>]?: never;
} & B)
| ({
[P in Exclude<keyof B | keyof C | keyof D | keyof E, keyof A>]?: never;
} & A)
| ({
[P in Exclude<keyof B | keyof A | keyof D | keyof E, keyof C>]?: never;
} & C)
| ({
[P in Exclude<keyof B | keyof A | keyof C | keyof E, keyof D>]?: never;
} & D)
| ({
[P in Exclude<keyof B | keyof A | keyof C | keyof D, keyof E>]?: never;
} & E)
type WeekDays = 0 | 1 | 2 | 3 | 4 | 5 | 6
type StringAndUnion<T> = T | (string & {})
type ArrayKeys<Arr extends any[] | readonly any[]> = keyof Arr & number
type PropsIntersection<T> = (T extends any ? (x: T) => void : never) extends (x: infer R) => void ? R : never
/** Giving a list of object, this will return a type similar to O1 & O2 & O3...
* * It works well when with this structure ```type ObjOfObj = Record<string, Record<string>>```
* * Giving that structure, if you want to extract ```ObjOfObj[keyof ObjOfObj]``` the type may
be never because its impossible to match O1 | O2...
*/
type MergeMultipleObjects<Obj extends Record<string, any>> = PropsIntersection<Obj[keyof Obj]>
/** Giving a list of required fields and subfields (dot notation) this type will return the object with the required fields added to type.
@example
```ts
type Obj = {
a: string;
aOptional?: string;
b: {
c?: string
d?: string
e: string
}
}
type RequiredFields = {
aOptional: true
'b.c': true
}
type Result = AddRequiredFieldsToObject<Obj, RequiredFields>
// PARSED TYPE:
type Obj = {
a: string
aOptional: string // this has became required because we specified it in RequiredFields
b: {
c: string // ALSO did this field
d?: string // this one has kept being optional
e: string // " " " " required
}
}
```
*/
type AddRequiredFieldsToObject<Obj extends Record<string, any>, RequiredFields extends Record<string, boolean>> = RemoveTypeFromObj<Required<{
[K in keyof Obj]:
K extends string
// ? Obj[K] extends any[] | readonly any[] ? Obj[K] :
? K extends keyof RequiredFields
? (RequiredFields[K] extends true
? IsObject<Obj[K]> extends true
? AddRequiredFieldsToObject<Obj[K], {
[P in keyof RequiredFields as P extends `${K}.${infer R}` ? R : never]: RequiredFields[P];
}>
: Obj[K]
: never)
: never
: never
}>, never> &
RemoveTypeFromObj<{
[K in keyof Obj]:
K extends string
// ? Obj[K] extends any[] | readonly any[] ? Obj[K] :
? K extends keyof RequiredFields
? never
: IsObject<Obj[K]> extends true
? AddRequiredFieldsToObject<Obj[K], {
[P in keyof RequiredFields as P extends `${K}.${infer R}` ? R : never]: RequiredFields[P];
}>
: Obj[K]
: never
}, never>
/**
* Removes the first element from a tuple type.
*
* @example
* ```ts
* type Example1 = RemoveFirst<[boolean, number, string]>; // [number, string]
* type Example2 = RemoveFirst<[boolean, string]>; // [string]
* type Example3 = RemoveFirst<[boolean]>; // []
* type Example4 = RemoveFirst<[]>; // never
* ```
*/
type RemoveFirstElementFromTuple<T extends any[]> = T extends [any, ...infer Rest] ? Rest : never;