Skip to content

Instantly share code, notes, and snippets.

@cleoold
Last active May 18, 2020 21:36
Show Gist options
  • Save cleoold/78a55b79d98e93a0b2572626224065d1 to your computer and use it in GitHub Desktop.
Save cleoold/78a55b79d98e93a0b2572626224065d1 to your computer and use it in GitHub Desktop.
remember type knowledge
/** https://www.typescriptlang.org/docs/handbook/advanced-types.html */
/** intersection type */
/** returns a new object with properties coming from two given objects */
const merge = <T extends object, S extends object>(first: T, second: S): T & S => {
const res: Partial<T & S> = {};
for (const prop in first)
if (first.hasOwnProperty(prop))
(<T>res)[prop] = first[prop];
for (const prop in second)
if (second.hasOwnProperty(prop))
(<S>res)[prop] = second[prop];
return <T & S>res;
}
/** type guard */
/** checks if x is number */
const isNumber = (x: any): x is number =>
typeof x === 'number';
/** type alias */
type Tree<T> = {
value: T,
nodes: Tree<T>[]
};
type LList<T> = T & {
next: LList<T> | null
};
/** index type */
type T001 = keyof { a: string, b: number } /** "a" | "b" */
/** gets o[propName] */
const getProp = <T, K extends keyof T>(o: T, propName: K): T[K] =>
o[propName];
/** creates list of mapped values given property names */
const pluck = <T, K extends keyof T>(o: T, propNames: K[]): T[K][] =>
propNames.map(n => o[n]);
/** object with string or number as keys, T as values */
type Dict<T> = {
[key: string]: T
};
type T002<T> = keyof Dict<T>; /** string | number */
type T003<T> = Dict<T>[0]; /** T */
type T004<T> = Dict<T>['0']; /** T */
/** object with number as keys, T as values */
type Arry<T> = {
[key: number]: T
};
type T005<T> = keyof Arry<T>; /** number */
type T006<T> = Dict<T>[0]; /** T */
/** mapped type */
/** type of object with readonly properties */
type MyReadonly<T> = {
readonly [K in keyof T]: T[K]
};
/** type of object with optional properties */
type MyPartial<T> = {
[K in keyof T]?: T[K]
};
/** type of object with nullable properties */
type MyNullableObject<T> = {
[K in keyof T]: T[K] | null
};
/** pick some keys K from type T */
type MyPick<T, K extends keyof T> = {
[P in K]: T[P]
};
type T007 = MyPick<{ a: string, b: string, c: string }, 'a' | 'b'>; /** { a: string, b: string } */
/** make type with keys K and values T */
type MyRecord<K extends keyof any, T> = {
[P in K]: T;
};
type T008 = MyRecord<'a' | 'b' | 'c', number>; /** { a: number, b: number, c: number } */
/** proxify */
type ProxifiedValue<V> = {
get(): V,
set(v: V): void
};
type ProxifiedObject<T extends object> = {
[P in keyof T]: ProxifiedValue<T[P]>
};
const proxify = <T extends object>(o: T): ProxifiedObject<T> => {
const res = {} as ProxifiedObject<T>;
for (const k in o) /** const k: Extract<keyof T, string> */
if (o.hasOwnProperty(k))
res[k] = {
get: () => o[k],
set: v => o[k] = v
}
return res;
}
const unproxify = <T extends object>(po: ProxifiedObject<T>): T => {
const res = {} as any;
for (const k in po)
res[k] = po[k].get();
return res;
};
/** conditional type */
type TypeName<T> =
T extends string ? 'string' :
T extends number ? 'number' :
T extends boolean ? 'boolean' :
T extends symbol ? 'symbol' :
T extends bigint ? 'bigint' :
T extends undefined ? 'undefined' :
T extends Function ? 'function' :
'object';
type T009 = TypeName<string | string[] | null | undefined>; /** "string" | "undefined" | "object" */
/** Remove types from T that are assignable to U */
type MyExclude/*Diff*/<T, U> = T extends U ? never : T;
type T010 = MyExclude<'a' | 'b' | 'c' | 0 , 'b' | number>; /** "a" | "c" */
//
/** extracts from T all properties that are assignable to U */
type MyExtract/*Filter*/<T, U> = T extends U ? T : never;
//
type T011 = MyExtract<'a' | 'b' | 'c' | 0 , 'b' | number>; /** 0 | "b" */
type T012<O> = MyExtract<keyof O, string> /** string properties of O */
/** remove null and undefined from T */
type MyNonNullable<T> = MyExclude<T, null | undefined>;
/** make object's properties non nullable */
type MyNonNullableObject<T> = {
[K in keyof T]: MyNonNullable<T[K]>
};
/** make object's all fields required (can't ?) */
type MyRequired<T> = {
[K in keyof T]-?: T[K]
};
type T013 = MyRequired<MyNonNullableObject<MyNullableObject<MyPartial<{ p: string }>>>> /** { p: string } */
/** names of methods of an object (result is union) */
type FunctionPropertyNames<T> = {
[K in keyof T]: T[K] extends Function ? K : never
}[keyof T];
/** names of non-function properties of an object */
type NonFunctionPropertyNames<T> = MyExclude<keyof T, FunctionPropertyNames<T>>;
/** methods of an object */
type FunctionProperties<T> = MyPick<T, FunctionPropertyNames<T>>;
/** non-methods of an object */
type NonFunctionProperties<T> = MyPick<T, NonFunctionPropertyNames<T>>;
/** inference */
/** parameter type of function */
type MyParameters<F extends Function> = F extends (..._: infer A) => any ? A : never;
/** return type of function */
type MyReturnType<F extends Function> = F extends(..._: any) => infer R ? R : never;
/** parameter type of constructor */
type MyConstructorParameters<F extends new (..._: any) => any> = F extends new (..._: infer A) => any ? A : never;
/** return type of constructor */
type MyInstanceType<F extends new (..._: any) => any> = F extends new (..._: any) => infer C ? C : never;
//
type T014 = MyInstanceType<typeof Boolean>; /** Boolean */
/** what value that matters will I get? */
type Unpacked<T> =
T extends (infer U)[] ? U :
T extends (..._: any) => infer U ? U :
T extends { new: (..._: any) => infer U } ? U :
T extends Promise<infer U> ? U :
T;
const T016 = () => Promise.resolve([ 0, 1, 2, 4, 8, 16, 32 ]);
type T015 = Unpacked<Unpacked<Unpacked< typeof T016 >>>; /** number */
/** question */
type Ex<T, U> = T extends U ? never : T;
/** type epic = "c" */
type epic = Ex<'a'|'b'|'c', 'a'|'b'>;
/** type unepic = "a" | "b" | "c" */
type unepic = ('a'|'b'|'c') extends ('a'|'b') ? never : ('a'|'b'|'c');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment