Skip to content

Instantly share code, notes, and snippets.

@ackvf
Last active January 18, 2023 01:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ackvf/72aee89e960d63ca417c2b1519fa46a7 to your computer and use it in GitHub Desktop.
Save ackvf/72aee89e960d63ca417c2b1519fa46a7 to your computer and use it in GitHub Desktop.
TypeScript sessions
import React from 'react';
import PropTypes from 'prop-types';
import { IMetricsServiceClient } from '@containers/App/model';
export interface IWithMetricsServiceClient {
metricsServiceClient: IMetricsServiceClient;
}
interface Options<MappedProp extends {} = IWithMetricsServiceClient> {
transform?: TransformType<MappedProp>;
}
type TransformType<MappedProp extends {} = IWithMetricsServiceClient> = (metricsServiceClient: IMetricsServiceClient) => MappedProp;
const defaultTransform: TransformType = (metricsServiceClient) => ({ metricsServiceClient });
function withMetricsServiceClient<OuterProps = {}, InnerProps extends {} = IWithMetricsServiceClient>(options?: Options<InnerProps>)
: (WrappedComponent: React.ComponentType<OuterProps & InnerProps>) => React.ComponentClass<OuterProps> {
return WrappedComponent =>
class extends React.Component<OuterProps> {
public static contextTypes = {
metricsServiceClient: PropTypes.object,
};
public render() {
return (
// @ts-ignore
<WrappedComponent
{...(options.transform || defaultTransform)(this.context.metricsServiceClient)}
{...this.props}
/>
);
}
};
}
export { withMetricsServiceClient };
export default withMetricsServiceClient;
const enhancer = withMetricsServiceClient<{outer: string}, {inner: string}>();
type ExtractGenerics<T> =
T extends React.ComponentType<infer G>
? G
: never;
type T01 = typeof enhancer
type T02 = Parameters<T01>
type T03 = T02 extends [React.ComponentType]
? T02[0]
: ['HOC must accept React.ComponentType, instead accepts', T02[0], 'did you forget to invoke it?']
type T04 = ExtractGenerics<T03>
type AnyFunction = (...args: any[]) => any;
type ExtractInnerInterface<T extends AnyFunction> =
ExtractGenerics<
Parameters<T> extends [React.ComponentType]
? Parameters<T>[0]
: ['HOC must accept React.ComponentType, instead accepts', Parameters<T>[0], 'did you forget to invoke it?']
>
type R1 = ExtractInnerInterface<typeof enhancer>;
type T05 = ReturnType<T01>
type T06 = T05 extends React.ComponentType
? T05
: ['HOC must return a single React.ComponentType, instead returns', T05]
type T07 = ExtractGenerics<T06>
type ExtractOuterInterface<T extends AnyFunction> =
ExtractGenerics<ReturnType<T> extends React.ComponentType
? ReturnType<T>
: ['HOC must return a single React.ComponentType, instead returns', ReturnType<T>]
>
type R2 = ExtractOuterInterface<typeof enhancer>;
/*
* Extracting infered types of function(...arguments[])
* 24.7.2019
*/
const withConsumers = <I extends {}>(
...allContexts: Array<React.Context<any>>
) => (Component: React.ComponentType<I>) => (props: I) =>
(function renderSlice(contexts, acumulatedProps) {
if (contexts.length) {
const Consumer = contexts.shift().Consumer;
return (
<Consumer>
{consumerValue =>
renderSlice(contexts, {
...acumulatedProps,
...consumerValue,
})
}
</Consumer>
);
} else {
return <Component {...props} {...acumulatedProps} />;
}
})(allContexts, {});
interface AContextProps { a: string; }
const AContext = React.createContext<AContextProps>({ a: 'AAA' });
interface BContextProps { b: number; }
const BContext = React.createContext<BContextProps>({ b: 42 });
interface CContextProps { c: boolean; }
const CContext = React.createContext<CContextProps>({ c: true });
interface MyProps { a: string; }
// const MyFunc: React.FC<MyProps> = ({a, b, c}) => <>{a} {b} {c}</>;
// const MyHoc = withConsumers<MyProps & React.ContextType<typeof BContext> & CContextProps>(BContext, CContext)
const MyHoc = withConsumers<MyProps>(BContext, CContext)
(
({ a, b, c }) => <>{a} {b} {c}</>
);
// CContextProps === React.ContextType<typeof CContext> === React.ContextType<React.Context<CContextProps>>;
const a: React.ContextType<typeof CContext> = { c: 'asd' };
const b: CContextProps = {c: 'xyz'};
type UnionToIntersection<U> = (U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never
type ExtractGenerics<T> =
T extends React.Context<infer G>
? G
: never;
type ExtractContextTypes<T> =
T extends Array<infer U>
? ExtractGenerics<U>
: T extends {}
? ExtractGenerics<T>
: never;
const A2 = [AContext, BContext, CContext];
type T2 = ExtractContextTypes<typeof A2>;
type T3 = ExtractContextTypes<typeof AContext>;
type T4 = ExtractContextTypes<typeof AContext | typeof BContext>;
const V2: T2 = {}
// the result is here ---------------------------------------------------------
function getContextTypes<T extends Array<React.Context<any>>>(...contexts: T): T extends Array<infer U> ? UnionToIntersection<ExtractContextTypes<U>> : any {
return void;
}
const V3 = getContextTypes(AContext, BContext)
const va = V3.a;
const V4: typeof V3 = {a: 'asd', b: 42};
const vb = V4.a;
type Foo<T> = T extends { a: infer U, b: infer U } ? U : never;
type T10 = Foo<{ a: string, b: string }>; // string
type T11 = Foo<{ a: string, b: number }>; // string | number
type Bar<T> = T extends { a: (x: infer U) => void, b: (x: infer U) => void } ? U : never;
type T20 = Bar<{ a: (x: string) => void, b: (x: string) => void }>; // string
type T21 = Bar<{ a: (x: string) => void, b: (x: number) => void }>; // string & number
/*
* Notino
* 09.2019
*/
import React from 'react';
type Modify<T, R> = Omit<T, keyof R> & R;
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
type AnyFunction = (...args: any[]) => any;
interface AnyObject {
[key: string]: any;
}
type ExtractComponentGenerics<T extends React.ComponentType> =
T extends React.ComponentType<infer G>
? G
: never;
type ExtractHOCIncomingProps<T extends AnyFunction> = ExtractComponentGenerics<ReturnType<T>>;
type ExtractHOCOutgoingProps<T extends AnyFunction> = ExtractComponentGenerics<Parameters<T>[0]>;
type ExtractHOCProps<T extends AnyFunction> = [ExtractHOCIncomingProps<T>, ExtractHOCOutgoingProps<T>];
type ExtractHOCAllIncomingProps<T extends AnyFunction[]> =
T extends Array<infer U>
? ExtractHOCIncomingProps<U>
: never;
type ExtractHOCAllOutgoingProps<T extends AnyFunction[]> =
T extends Array<infer U>
? ExtractHOCOutgoingProps<U>
: never;
type HigherOrderComponent<IncomingProps = {}, OutgoingProps = {}> = (wrapped: React.ComponentType<OutgoingProps & IncomingProps>) => React.ComponentType<IncomingProps>;
type HOC<IncomingProps = {}, OutgoingProps = {}> = HigherOrderComponent<IncomingProps, OutgoingProps>;
type Head<T extends any[]> =
T extends [any, ...any[]]
? T[0]
: never;
type Tail<T extends any[]> =
((...t: T) => any) extends ((_: any, ...tail: infer U) => any)
? U
: [];,
type HasTail<T extends any[]> =
T extends ([] | [any])
? false
: true;
// ----------------------------------------------------------------------------
interface A { a: number; }
interface B { b: number; }
interface C { c: number; }
interface HIn { hin: string; }
interface HOut { hout: string; hout2: string; }
interface HIn2 { h2in: string; hout2: number; }
interface HOut2 { h2out: string; h2out2: string; }
interface CIn extends HIn, HOut { cin: number; }
interface CXIn extends HOut { cin: number; }
interface XOut { xout: number; }
declare const Hoc: HOC<HIn, HOut>;
declare const Hoc2: HOC<HIn2, HOut2>;
const MyComponent: React.FC<CIn> = ({}) => <span>asd</span>;
// ----------------------------------------------------------------------------
/*
const H = Hoc(MyComponent); // = React.ComponentType<HIn>
// returns included incoming and outgoing props
const fns = [Hoc, Hoc2];
type P = ExtractHOCAllIncomingProps<typeof fns>; // = HIn | HIn2
type R = ExtractHOCAllOutgoingProps<typeof fns>; // = (HOut & HIn) | (HOut2 & HIn2)
type P1 = UnionToIntersection<P>; // = HIn & HIn2
type R1 = UnionToIntersection<R>; // = HOut & HIn & HOut2 & HIn2
*/
// ----------------------------------------------------------------------------
declare const H1: HOC<{}, { a: string, b: string }> = wrapped /* ({a, b}) */ => ({ }) => <span>{wrapped}</span>;
declare const H2: HOC<{ a: string }, { c: number }> = wrapped /* ({a, c}) */ => ({ a }) => <span>{wrapped}</span>;
declare const C1: React.FC<{ a: string, b: string, c: number }>;
declare function compost<P extends AnyFunction[]>(...fns: P): Compost<P>;
type Compost<IncomingProps = {}, P extends AnyFunction[] = [], PreviousHOCProps = IncomingProps> =
(fn: Head<P>, ...fns: AnyFunction[]) => HasTail<P> extends true ? Compost<{}, typeof fns, {}> : false;
type Overlaps<G, A, B> = B extends Partial<G & A> ? true : false;
type T02 = Overlaps<{c: string, d: string}, {a: string, b: string}, {c: string}>;
type T01 = ExtractHOCProps<typeof H1>;
const fns = [H1, H2];
declare function head<T extends any[]>(...args: T): Head<T>;
const v1 = head(H1, H2);
const v2 = compost(H1, H2);
type T03 = typeof v2;
declare function ccc<P extends {}, R1 extends P, P2 extends R1, R2 extends P2, P3 extends R2, R3 extends P3>(f1: (p: P) => R1, f2: (p: P2) => R2, f3: (p: P3) => R3):
(props: P) => R3;
function c1<P1 extends {}, P extends P1, R1 extends P>(f1: (p: P1) => R1): (props: P) => R1 { return f1; }
// declare function c2<P1 extends {}, R1, R extends R1, T extends HOC>(f1: HOC<P1, R1>): T extends (wrapped: React.ComponentType<infer U>) => React.ComponentType<any> ? HOC<P1 & U, U> : never;
declare function c2<P1 extends {}, R1, R extends R1, T extends HOC>(f1: HOC<P1, R1>): T extends (wrapped: (props: infer U) => React.ReactElement | null) => React.ComponentType ? number : string;
const f1: (props: A) => A & B = ({ a }) => ({a, b: 2});
let r1 = c1(({a, ...rest}: A) => ({...rest, a: a + 1, b: 2}))({a: 1, b: 2});
let R2 = c2(H2);
const R2A = <R2 />;
// ----------------------------------------------------------------------------
const pipe: <R>(fn1: (a: R) => R, ...fns: Array<(a: R) => R>) => R = (fn1, ...fns) =>
fns.reduce((prevFn, nextFn) => value => nextFn(prevFn(value)), fn1);
let fn1 = val => ({ ...val, a: 1});
let fn2 = val => ({ ...val, b: 2});
let fn3 = val => ({ ...val, c: 3});
let piped = pipe(fn1, fn2, fn3)
// pipe(f1, f2, f3, f4)
// A: [f1, f2] : v1 => f2(f1(v1))
// B: [A, f3] : v2 => f3(A(v2)) : v2 => f3((v1 => f2(f1(v1)))(v2))
// C: [B, f4] : v3 => f4(B(v3)) : v3 => f4((v2 => f3((v1 => f2(f1(v1)))(v2)))(v3))
/*
* Notino
* 09.2019
*/
import React from 'react';
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
type AnyFunction = (...args: any[]) => any;
type ExtractComponentGenerics<T extends React.ComponentType> =
T extends React.ComponentType<infer G>
? G
: never;
type ExtractHOCIncomingProps<T extends AnyFunction> = ExtractComponentGenerics<ReturnType<T>>;
type ExtractHOCOutgoingProps<T extends AnyFunction> = ExtractComponentGenerics<Parameters<T>[0]>;
type ExtractHOCProps<T extends AnyFunction> = [ExtractHOCIncomingProps<T>, ExtractHOCOutgoingProps<T>];
type ExtractHOCAllIncomingProps<T extends AnyFunction[]> =
T extends Array<infer U>
? ExtractHOCIncomingProps<U>
: never;
type ExtractHOCAllOutgoingProps<T extends AnyFunction[]> =
T extends Array<infer U>
? ExtractHOCOutgoingProps<U>
: never;
type ExclusiveHigherOrderComponent<IncomingProps, OutgoingProps> = (wrapped: React.ComponentType<OutgoingProps>) => React.ComponentType<IncomingProps>;
type ExclusiveHOC<IncomingProps, OutgoingProps> = ExclusiveHigherOrderComponent<IncomingProps, OutgoingProps>;
type HigherOrderComponent<IncomingProps, OutgoingProps> = ExclusiveHigherOrderComponent<IncomingProps, OutgoingProps & IncomingProps>;
type HOC<IncomingProps, OutgoingProps> = HigherOrderComponent<IncomingProps, OutgoingProps>;
type Tail<T extends any[]> =
((...t: T) => any) extends ((_: any, ...tail: infer U) => any)
? U
: [];,
type HasTail<T extends any[]> =
T extends ([] | [any])
? false
: true;
// ----------------------------------------------------------------------------
interface HIn { hin: string; }
interface HOut { hout: string; hout2: string; }
interface HIn2 { h2in: string; hout2: number; }
interface HOut2 { h2out: string; h2out2: string; }
interface CIn extends HIn, HOut { cin: number; }
interface CXIn extends HOut { cin: number; }
interface XOut { xout: number; }
declare const Hoc: HOC<HIn, HOut>;
declare const Hoc2: HOC<HIn2, HOut2>;
declare const HocX: ExclusiveHOC<HIn, HOut>; // incoming props are not returned from HOC
declare const HocX2: ExclusiveHOC<HIn2, HOut2>;
const MyComponent: React.FC<CIn> = ({}) => <span>asd</span>;
const MyComponentX: React.FC<CXIn> = ({}) => <span>asd</span>;
// ----------------------------------------------------------------------------
const H = Hoc(MyComponent); // = React.ComponentType<HIn>
const HX = HocX(MyComponentX); // = React.ComponentType<HIn>
// returns included incoming and outgoing props
const fns = [Hoc, Hoc2];
type P = ExtractHOCAllIncomingProps<typeof fns>; // = HIn | HIn2
type R = ExtractHOCAllOutgoingProps<typeof fns>; // = (HOut & HIn) | (HOut2 & HIn2)
type P1 = UnionToIntersection<P>; // = HIn & HIn2
type R1 = UnionToIntersection<R>; // = HOut & HIn & HOut2 & HIn2
// consumes incoming props and returns outghoing props
const fnsx = [HocX, HocX2];
type PX = ExtractHOCAllIncomingProps<typeof fnsx>; // = HIn | HIn2
type RX = ExtractHOCAllOutgoingProps<typeof fnsx>; // = HOut | HOut2
type P1X = UnionToIntersection<PX>; // = HIn & HIn2
type R1X = UnionToIntersection<RX>; // = HOut & HOut2
// ----------------------------------------------------------------------------
declare const H1: HOC<{}, {a: string, b: string}>;
declare const H2: HOC<{ a: string }, { c: number }>;
declare const compost: Compost;
type Compost/* <P extends any[], R> */ =
(...fns: any[]) => typeof fns[0] extends HOC<infer I, infer O> ? [I, O] : never;
type Overlaps<G, A, B> = B extends Partial<G & A> ? true : false;
type T02 = Overlaps<{c: string, d: string}, {a: string, b: string}, {c: string}>;
type T01 = ExtractHOCProps<typeof H1>;
let i = compost(H1, H2);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment