Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
    Pierre-Antoine Mills
    @millsp
    Yes you are right
    Anything that can be pre-generated should be stored in the map itself
    Would you mind opening an issue?
    Kristóf Poduszló
    @kripod
    Sorry, I forgot to, but I see that the performance has increased a lot. Thank you!
    Chris Swithinbank
    @delucis

    Hey everyone! Wondering about a way to type a “configurable” object containing methods based on an input object.

    For example, given a configuration like the following:

    const config = [
      { name: 'A', fn: () => 'Hello' },
      { name: 'B', fn: (n: number) => n * 2 },
    ]

    We would return an API with an interface like:

    interface API {
      A: () => 'Hello';
      B: (n: number) => number;
    }

    The mapping could happen something like this:

    const makeAPI = <T extends Something?>(config: T) => {
      const api = {} // as SomethingElse<T>?
      config.forEach(obj => { api[obj.name] = obj.fn })
      return api
    }

    Is it possible to type something like this, so that the function types are tied to their names?

    Pierre-Antoine Mills
    @millsp
    @delucis yes it's possible, but only if your type is a constant
    const config = [
        {name: 'A', fn: () => 'Hello'},
        {name: 'B', fn: (n: number) => n * 2},
    ] as const
    
    type Config = typeof config
    
    type API = U.IntersectOf<O.UnionOf<{
        [K in Exclude<keyof Config, keyof any[]>]: O.Record<O.At<Config[K], 'name'>, O.At<Config[K], 'fn'>>
    }>>
    Chris Swithinbank
    @delucis
    Oh, wow. That’s magic!
    I can more or less follow it all but how does the Exclude generic operate on those keys? Is it just excluding all the array prototype methods? So, keys 0, 1 are left, because they are not known to exist on any[]?
    Thanks so much!
    Chris Swithinbank
    @delucis

    So great, needed a couple of tweaks, but managed to get this working as a generic:

    type API<Config> = U.IntersectOf<
      O.UnionOf<
        {
          [K in Exclude<keyof Config, keyof any[]>]: Config[K] extends {
            name: A.Key;
            fn: F.Function;
          }
            ? O.Record<O.At<Config[K], "name">, O.At<Config[K], "fn">>
            : never;
        }
      >
    >;

    Thanks again!

    Pierre-Antoine Mills
    @millsp
    @delucis Yep you got it! The Exclude is indeed to remove array prototype methods. Cheers
    Patrick Roza
    @patroza

    I have a structure; either an Array, or an Object, and then recursively more Arrays, Objects, with primitives etc,
    but also with fp-ts's O.Option<T>'s, I want to replace all the Option<T>'s with T | null, recursively not only within Arrays or Objects, but also inside the Option<T>'s themselves; as they may also contain arrays or objects etc.
    so far any of my trials result in Typescript bombing out because I make circular references in my types...

    anyone any idea if the toolbelt has the right tools for the job?

    Pierre-Antoine Mills
    @millsp
    Hey @patroza there's almost nothing we can't do. I don't know fp-ts, could you instead explain what the type must do for you? If you can give me an example input and the expected output, I'll most likely be able to help you
    Patrick Roza
    @patroza

    hi, thanks @pirix-gh:

    type SomeObject = {
      a: { b: O.Option<string> },
      c: { d: Array<O.Option<{e: O.Option<boolean>}>> }
    }

    Convert that to:

    type ConvertedSomeObject = {
       a: { b: string | null },
       c: { d: Array<{ e: boolean | null } | null> }
    }

    similarly:
    type X = Array<SomeObject>
    ->
    type ConvertedX = Array<ConvertedSomeObject>

    similarly:
    type Y = O.Option<{ a: O.Option<string> }>
    ->
    type ConvertedY = { a: string | null } | null

    but the Object or Array as root are the more important cases.

    so: Replace all O.Option<T> with T | null

    Patrick Roza
    @patroza
    For completeness, this is the accompanying code:
    const encodeOptionsAsNullable = (value: any, cacheMap: Map<any, any>): any => {
      const cacheEntry = cacheMap.get(value)
      if (cacheEntry) {
        return cacheEntry
      }
      if (Array.isArray(value)) {
        const newAr: typeof value = []
        cacheMap.set(value, newAr)
        value.forEach((x) => newAr.push(encodeOptionsAsNullable(x, cacheMap)))
        return newAr
      }
      if (value instanceof Object) {
        if (value._tag === "Some" || value._tag === "None") {
          return encodeOptionsAsNullable(O.toNullable(value), cacheMap)
        }
        const newObj = {} as Record<string, any>
        cacheMap.set(value, newObj)
    
        Object.keys(value).forEach((key) => {
          newObj[key] = encodeOptionsAsNullable(value[key], cacheMap)
        }, newObj)
        return newObj
      }
      return value
    }
    Pierre-Antoine Mills
    @millsp

    @patroza this should do, you're welcome to ask questions

    import {C, U} from 'ts-toolbelt'
    import {Option, Some, None} from 'fp-ts/lib/Option'
    
    type SomeObject = {
        0: Option<string>,
        a: { b: Option<string> },
        c: { d: Array<Option<{e: Option<boolean>}>> }
    }
    
    type OptionOf<A> =
        U.Exclude<
            A extends Some<infer X>
            ? X | null
            : A,
            None
        >
    
    type Transform<O> = {
        [K in keyof O]: OptionOf<O[K]> extends infer X
                        ? X extends (infer Y)[]
                          ? OptionOf<Transform<Y>>[]
                          : X extends object
                            ? Transform<X>
                            : X
                        : never
    
    } & {}
    
    type test0 = Transform<SomeObject>

    Remove the & {} if you plan to work on nested types.

    Pierre-Antoine Mills
    @millsp
    @patroza please remember to give a star. Thanks!
    Patrick Roza
    @patroza
    @pirix-gh Thanks a lot, will try this now!
    Patrick Roza
    @patroza
    works a dream; thanks so much! starred for sure. been using some of the toolbelt like A.Compute and few others so far. my brain is fried from a long hard week, but I hope to dissect it a bit in the weekend to understand how this works!
    Patrick Roza
    @patroza

    it looks like Date is coming out strangely, I made an exclusion like this:

    type Passthrough = Date
    
    export type Transform<O> = {
      [K in keyof O]: OptionOf<O[K]> extends infer X
        ? X extends (infer Y)[]
          ? OptionOf<Transform<Y>>[]
          : X extends Passthrough
          ? X
          : X extends object
          ? Transform<X>
          : X
        : never
    } & {}

    To resolve this:
    Type '{ createdAt: { toString: {}; toDateString: {}; toTimeString: {}; toLocaleString: {}; toLocaleDateString: {}; toLocaleTimeString: {}; valueOf: {}; getTime: {}; getFullYear: {}; getUTCFullYear: {}; ... 32 more ...; toJSON: {}; }; ... 12 more ...;

    Pierre-Antoine Mills
    @millsp

    Ouch, thanks for pointing this out. This is a problem because Date gets resolved as object, like Regexp or Promise. We should filter out all the std built-in objects to avoid this. That's my modified version.

    type Transform<O> = 
    O extends Date | RegExp | Function | Promise<any> ? O : {
        [K in keyof O]: OptionOf<O[K]> extends infer X
                        ? X extends (infer Y)[]
                          ? OptionOf<Transform<Y>>[]
                          : Transform<X>
                        : never
    
    }

    This is definitely something I should check on the ts-toolbelt. I think I'll have to create a "built-in type" so that we can do O extends BuiltInObject ? .... Please note that the modified version does not integrate all buil-in types (bigint), I should work on this!

    And I also excluded Function because mapping over it makes it become an empty object.

    Patrick Roza
    @patroza

    Merci beaucoup! very nice. good point regarding function & Promise.
    in graphql these may be valid types too, but I think any function or Promise should be it's own "root" again and apply conversion accordingly.
    I personally don't have the usecase for it right now.

    A built-in types type sounds good.

    Pierre-Antoine Mills
    @millsp

    @patroza you can now use the safer version

    type Transform<O> = 
    O extends M.BuiltInObject ? O : {
        [K in keyof O]: OptionOf<O[K]> extends infer X
                        ? X extends (infer Y)[]
                          ? OptionOf<Transform<Y>>[]
                          : Transform<X>
                        : never
    }

    cheers

    Pierre-Antoine Mills
    @millsp
    In some sense, BuiltInObject represents anything we would not want to map over. Just update to the latest version to get it.
    Patrick Roza
    @patroza
    Nice, thanks a lot! Would there be a version that would work with the root object being an Option?
    Patrick Roza
    @patroza
    My idea so far:
    export type TransformRoot<O> = O extends O.Some<infer Y>
      ? Transform<Y> | null
      : Transform<O>
    Patrick Roza
    @patroza
    This works better:
    export type TransformRoot<O> = O extends O.Option<any>
      ? Transform<OptionOf<O>>
      : Transform<O>
    Pierre-Antoine Mills
    @millsp
    @patroza looks good to me, it's clearer this way too. You can just rename Transform to a more meaningful name then you're all set. Here's my (more complicated) version ^^:
    type Transform<O, _O = OptionOf<O>> = 
    _O extends M.BuiltInObject ? _O : {
        [K in keyof _O]: OptionOf<_O[K]> extends infer X
                        ? X extends (infer Y)[]
                          ? OptionOf<Transform<Y>>[]
                          : Transform<X>
                        : never
    }
    I actually prefer yours, it's easier to read
    Patrick Roza
    @patroza
    hi again @pirix-gh, I found out that the BuiltInObject does not include readonly any[],
    bit me today. you may want to add it, and perhaps it exposes other similar missing cases?
    Pierre-Antoine Mills
    @millsp
    Hey @patroza, sorry for taking so long. The fix will be out in a few minutes!
    And stay tuned for the upcoming 7.0 that will bring great performance improvements with TypeScript 4.0
    Ben Grynhaus
    @bengry
    Hey, is there a way to get a true DeepMerge type working? Specifically when you have arrays along the way. See this (broken) example: https://codesandbox.io/s/pensive-franklin-3xn39?file=/src/index.ts:239-264
    Paweł Sacawa
    @psacawa
    Hello, I would like to report that the docuemntation seems to be wrong in at least one point: at https://millsp.github.io/ts-toolbelt/modules/_any_pick_.html, it reports that Pick can be found in the Union module. In actuality, I find it in the Object module.
    Pierre-Antoine Mills
    @millsp
    @psacawa thanks for pointing this out! Will fix soon!
    Wessel van der Veen
    @wesselvdv
    @millsp I have a question regarding the A.Compute<> type provided. It seems to be incorrectly computing arrays. (e.g. it's pulling them apart as if it's an object instead of keeping it as an array.)
    import { A, M } from 'ts-toolbelt';
    import { Depth } from 'Object/_Internal';
    type ComputeFlat<A extends any> = A extends M.BuiltInObject
      ? A
      : A extends Array<any>
      ? A extends Array<Record<string | number | symbol, any>>
        ? Array<
            {
              [K in keyof A[number]]: A[number][K];
            } & {}
          >
        : A
      : A extends ReadonlyArray<any>
      ? A extends ReadonlyArray<Record<string | number | symbol, any>>
        ? ReadonlyArray<
            {
              [K in keyof A[number]]: A[number][K];
            } & {}
          >
        : A
      : {
          [K in keyof A]: A[K];
        } & {};
    
    type ComputeDeep<A extends any> = A extends M.BuiltInObject
      ? A
      : A extends Array<any>
      ? A extends Array<Record<string | number | symbol, any>>
        ? Array<
            {
              [K in keyof A[number]]: ComputeDeep<A[number][K]>;
            } & {}
          >
        : A
      : A extends ReadonlyArray<any>
      ? A extends ReadonlyArray<Record<string | number | symbol, any>>
        ? ReadonlyArray<
            {
              [K in keyof A[number]]: ComputeDeep<A[number][K]>;
            } & {}
          >
        : A
      : {
          [K in keyof A]: ComputeDeep<A[K]>;
        } & {};
    
    export type Compute<A extends any, depth extends Depth = 'deep'> = {
      flat: ComputeFlat<A>;
      deep: ComputeDeep<A>;
    }[depth];
    
    type test = {
      a: ReadonlyArray<{
        a: number;
        c: ReadonlyArray<{
          a: number;
        }>;
      }>;
      b: { a: number };
    } & {
      a: ReadonlyArray<{
        d: Array<{
          b: number;
        }>;
        c: ReadonlyArray<{
          b: number;
        }>;
      }>;
      c: { c: number };
    };
    
    // fixed variant (or I think it's fixed)
    type a = Compute<test>;
    // ts-toolbelt one
    type c = A.Compute<test>;
    I would argue that in the example above the variant I did (probably not the cleanest ts type code), results in an easier to grasp type than the one currently included in ts-toolbelt.
    Pierre-Antoine Mills
    @millsp
    Hey @wesselvdv, thanks for pointing this out. The reason why, I have chosen this implementation is that I haven't found a solution that can handle tuples, arrays, and possible intersections between them without compromising performance (folks use Compute on very large objects sometimes)
    Wessel van der Veen
    @wesselvdv
    Alright, so my implementation is a naive one? I have yet to have performance issues with it.
    Pierre-Antoine Mills
    @millsp
    I just looked at it and the results look quite good.
    I'm going to do further performance tests
    Wessel van der Veen
    @wesselvdv
    And did you get anything useful from it?
    Kositsky Alexandr
    @felixcatto
    Hi guys. I have a silly question. When i try to use any value on List, Object ... i get a error
    Selection_005.png
    Selection_007.png
    So i got all objects from library with depth 1. But they are empty. So it just does not work. Which is strange, because it seems that only i have such problem
    Kositsky Alexandr
    @felixcatto
    But this import works as expected
    import { ObjectOf } from 'ts-toolbelt/out/List/_api';
    Pierre-Antoine Mills
    @millsp
    Strange, can you please open an issue?
    adelin-b
    @adelin-b

    Hello ! Im trying to rename all the keys in an interface using ts-toolbelt

    from this

    {
    findX: ()=> X
    }

    to this

    {
    getX: ()=>X
    }

    I have the rename method :

    const method = "findHello"; 
    type FindToGet<Method> = `get${Method extends `find${infer X}` ? X : never}`; 
    const methodGet: FindToGet<typeof method> = "getHello";

    And now I need to "apply" it on every key. I thought ts-toolbelt could help me but I dont find the function in Object.
    Any pointers ?