#Generic parameter is another generic

1 messages · Page 1 of 1 (latest)

abstract cloudBOT
#
onkeltem#0

Preview:```ts
export type Obj = Record<string, unknown>;

type Field<T> = {
title: string;
value: T;
};

type Describe<T> = T extends Obj
? {
[K in keyof T]: T[K] extends Obj ? Describe<T[K]> : Field<T[K]>;
}
: never;

// How to implement a version of DescribeEx that accepts Describer as a parameter?
...```

empty crag
#

How to implement a version of DescribeEx that accepts Describer as a parameter?

#

In the first example, the Describer type is Field

#

But I'm seeking for a way to pass alternative describers

#

Because in RL my Describe type is more complex

#

It's something like this:

// prettier-ignore
type Describe<T> = T extends Obj
  ? {
      [K in keyof T]: T[K] extends Obj[][]      // Array of arrays of objects?
        ? T[K] extends (infer P)[][] 
          ? Describe<P>[][]
          : never
        : T[K] extends Obj[]                    // Array of objects?
          ? T[K] extends (infer P)[]
            ? Describe<P>[]
            : never
          : T[K] extends unknown[]
            ? ArrayElementField
            : T[K] extends Obj                  // Object
              ? Describe<T[K]>
              : Field<T[K]>;                    // Scalar, leaf
#

So what it does, or rather should do, - it's repeating the original structure of the type but replaces all leafs with a cluster of props.

#

So if it were:
{foo: string}
it would turn into something like this:
{foo: {title: string, value: string, formattedValue: string}}

#

So the problem I'm facing now is how to declare a generic (Describe) that takes second parameter (like Field) which is also a generic.

scarlet tundra
#

I think you can't. When you use a generic you need to specify the type parameters for it.

empty crag
scarlet tundra
#

You can't AFAIK

empty crag
#

Hm... Ok, then probably there is another approach

scarlet tundra
#

When they pass the type to your generic type, they are "using" it so need to declare the type param.

#

yeah

empty crag
#

Because it seems to me a pretty regular task for TS: take a type and "apply" it recursively

#

Ok, so my describers should be a type with default param them

scarlet tundra
#

I've never needed it myself

scarlet tundra
empty crag
#

Hmmm

scarlet tundra
#

Maybe I'm wrong, but I have a feeling this is a hard no

#

Your consumer can implement DescribeEx themself to acheive the type

empty crag
#

That's the problem. They could need their custom Describer, but they don't want to repeat my entire Describe type

scarlet tundra
#

"Deal with it"

#

You might be able to make an extendable interface

empty crag
#

Meh I see. At first I thought I'd forgotten something simple

scarlet tundra
#

actually maybe not even that

#

Is this DescribeEx gonna be big and complicated?

empty crag
scarlet tundra
#

I see

empty crag
#

So I just need to replace Field there with something generic

#

with a param

scarlet tundra
#

Annoying isn't it

#

If Field<T[K]> can only do a limited number of things there might be a way

#

Or to derive Field from a type argument

#

LIke if Field is T & something, then you can take something and derive Field

#

But if it's totally flexible I don't see any way

empty crag
#

Ok, I can actually live without this. Let them repeat my entire Describe type for their specific Field flavor

#

Thanks @scarlet tundra

#

LOL I can't even do something like this:

#
type GenericDescriber<T = never> = {}

type DescribeEx<T, Describer extends GenericDescriber> = T extends Obj
  ? {
      [K in keyof T]: T[K] extends Obj ? DescribeEx<T[K], Describer> : Describer extends GenericDescriber<infer P> ? Describer<T[K]> : never;
    }
  : never;

It says: Type 'Describer' is not generic. I think that's exactly what you've said about Generic being calculaed before

scarlet tundra
#

Now let's wait for someone to come and say I'm wrong and you can do it really 😉

#

Yeah GenericDescriber is evaluated immediately to genericDescriber<never>

empty crag
#

yep

scarlet tundra
#

I remember trying to infer the T of a generic and that not working too, without that issue :/