Last active
June 5, 2025 11:32
-
-
Save miladvafaeifard/424827610758a53fecb7fb591ea8e883 to your computer and use it in GitHub Desktop.
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
/************************************* Check Object Empty *********************/ | |
type IsKeyIn<T> = T extends object ? keyof T: never; | |
type IsEmptyObject<T> = IsKeyIn<T> extends never ? 'Yes' : 'No'; | |
type OBJ<T> = T extends object ? | |
IsEmptyObject<T> extends 'Yes' ? never : { [P in keyof T]: T[P] } | |
: never; | |
type newMap = OBJ<{}> | |
// never | |
/************************************* Get Nested Keys *********************/ | |
type Keys<T> = | |
T extends object | |
? { [K in keyof T]: K | Keys<T[K]> }[keyof T] | |
: never; | |
interface A { | |
a: string; | |
b: { | |
c: string; | |
}; | |
} | |
type Result = Keys<A>; // a | b | c | |
/************************************* Object.keys *********************/ | |
https://fettblog.eu/typescript-better-object-keys/ | |
type ObjectKeys<T> = | |
T extends object ? (keyof T)[] : | |
T extends number ? [] : | |
T extends any[] | string ? string[] : | |
never; | |
export interface ObjectConstructor { | |
keys<T>(o : T): ObjectKeys<T>; | |
} | |
type Person = { | |
name: string, age: number, id: number, | |
} | |
const me: Person; | |
Object.keys(me).forEach(key => { | |
// typeof key = 'id' | 'name' | 'age' | |
console.log(me[key]) | |
}) | |
/************************************* omit keys *********************/ | |
export type DistributiveOmit<T, K extends keyof T> = T extends unknown | |
? Omit<T, K> | |
: never; | |
export type IncludeOnlyOfType<T, TP> = { | |
[P in keyof T]: T[P] extends TP ? P : never; | |
}; | |
export type KeysOfType<T, TP> = IncludeOnlyOfType<T, TP>[keyof T]; | |
/************************************* Return Type consecutive functions *********************/ | |
type isFunction = (a: any | any[]) => any | any[] | undefined | null; | |
type ExtractReturnType<T> = T extends isFunction | |
? ExtractReturnType<ReturnType<T>> | |
: T; | |
type LazyFirst<T> = (items: T[]) => (filter: (item: T) => boolean) => T | undefined | |
const lazyFirst: LazyFirst<number> = items => filter => { | |
return items.find(filter); | |
} | |
type Test = ExtractReturnType<typeof lazyFirst> | |
/************************************* Common Others *********************/ | |
type Head<T extends any[]> = T extends [] ? never : T[0]; | |
type Take<T extends any[], num extends number> = | |
T extends [] ? never | |
: T[num] extends (undefined | null) ? never | |
: T[num]; | |
/************************************ Generate Properties **********/ | |
// Youtube link: https://www.youtube.com/live/2XfhoQY9M7g?si=s0LWpyUcut5oJFKb&t=5104 | |
type NameReturn<T extends string> = { [Key in T as `select${Capitalize<Key>}State`]: string; } | |
function sayHi<Name extends string>(msg: Name): NameReturn<Name> { | |
return { | |
[`select${msg}State`]: 'Hello' | |
} as NameReturn<Name> | |
} | |
const fn = sayHi('milad'); | |
fn.selectMiladState | |
/************************************ Object Merging **********/ | |
// https://www.youtube.com/watch?v=jEeQC6I8nlY | |
type Prettify<T> = {[ Prop in keyof T]: T[Prop]} & {} | |
type Merge<T1, T2> = Prettify<Omit<T1, keyof T2> & T2> | |
type MergeArrayOfObjects< | |
TArr extends readonly object[], | |
T1 = {} | |
> = TArr extends [ | |
infer T2 extends object, | |
...infer TRest extends object[] | |
] ? | |
MergeArrayOfObjects<TRest, Merge<T1, T2>> | |
: T1 | |
function merge<TArr extends readonly object[]>(...arg: TArr): MergeArrayOfObjects<TArr> { | |
return Object.assign({}, ...arg); | |
} | |
const merged = merge( | |
{foo: 122, bar: 'hello'}, | |
{foo: 'bye'} | |
) | |
/****** loose-autocomplete ****/ | |
type ModelNames = | |
| "gpt-40 | |
| "gpt-41 | |
| "Claude-3.5" | |
| (string & {}) | |
const modelName: ModelNames = "akawed" // works but shows autocomplete list | |
/****** Miscellaneous ***/ | |
export type WithOptional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T,K>>; | |
export type WithRequired<T, K extends keyof T> = Omit<T, K> & Required<Pick<T,K>>; | |
export type KebabCase<T extends string, Target extends string, Replacer extends string> = T extends `${infer Left}${Target}${infer Right}` | |
? `${Left}${Replacer}${KebabCase<Right, Target, Replacer>}` : T; | |
type NonEmptyString<T extends string> = Trim<T> extends "" ? never : Trim<T>; | |
type Test = NonEmptyString<"">; // should be never | |
type Test2 = NonEmptyString<"Hello">; // should be "Hello" | |
type Test3 = NonEmptyString<" ">; // should be "Hello World" | |
type TrimLeft<T extends string> = T extends ` ${infer Rest}` ? TrimLeft<Rest> : T; | |
type TrimRight<T extends string> = T extends `${infer Rest} ` ? TrimRight<Rest> : T; | |
type Trim<T extends string> = TrimLeft<TrimRight<T>>; | |
type TestTrim1 = Trim<" Hello World ">; // should be "Hello World" | |
type TestTrim2 = Trim<"Hello World">; // should be "Hello World" | |
type TestTrim3 = Trim<" ">; // should be "" | |
type TestTrim4 = Trim<"">; // should be "" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment