Skip to content

Instantly share code, notes, and snippets.

@miladvafaeifard
Last active June 5, 2025 11:32
Show Gist options
  • Save miladvafaeifard/424827610758a53fecb7fb591ea8e883 to your computer and use it in GitHub Desktop.
Save miladvafaeifard/424827610758a53fecb7fb591ea8e883 to your computer and use it in GitHub Desktop.
/************************************* 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