Last active
January 18, 2023 01:04
-
-
Save ackvf/72aee89e960d63ca417c2b1519fa46a7 to your computer and use it in GitHub Desktop.
TypeScript sessions
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
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>; |
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
/* | |
* 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 |
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
/* | |
* 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)) |
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
/* | |
* 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