#How can I extract instance types based on provided class types?

1 messages · Page 1 of 1 (latest)

past swan
#

I want to create a function that accepts classes (not instances) and the returns class instance types. This is what I want to achieve:

class A { a: number };

class B { a: string };

const view = createView(A, B);
// typeof view == [A, B]

So far, I created a generic that recursively convert the class instance type to a class:

class Component1 {
  public declare a : number;
  }

class Component2 {
  public declare b : number;
}

type ComponentClass<TComponent, TArgs extends unknown[]> = {
  new (...args: TArgs): TComponent;
};

type WrapInClasses<T extends unknown[]> = T extends [infer R, ...infer U] ? [ComponentClass<R, unknown[]>, ...WrapInClasses<U>] : []

type Res = WrapInClasses<[Component1, Component2]>
// Res = [ComponentClass<Component1, unknown[]>, ComponentClass<Component2, unknown[]>]

This part works; however, when I try to use in a function, I keep getting error about type mismatch:

const createView = <T extends unknown[]>(...args: WrapInClasses<T>): T => {
  // Do not care about the internals for now
  return null as any;
}

const view = createView(Component1, Component2);
// Error: Expected 0 arguments, got 2

When I hover over the function call, the type that I am getting is the following:

const createView: <unknown[]>() => unknown[]

If I provide a type in the generic, everything works as expected:

const view2 = createView<[Component1, Component2]>(Component1, Component2);
// typeof view2 = [Component1, Component2]

Is there a way that I can make the function infer the types instead of forcefully passing the types?

sour coyoteBOT
#

@past swan Here's a shortened URL of your playground link! You can remove the full link from your message.

_liquido#0

Preview:```ts
class Component1 {
public declare a: number
}

class Component2 {
public declare b: number
}

type ComponentClass<
TComponent,
TArgs extends unknown[]

= {
new (...args: TArgs): TComponent
}

type WrapInClasses<T extends unknown[]> = T extends [
infer R,
...infer U
]
? [ComponentClass<R, unknown[]>, ...WrapInClasses<U>]
: []
...```

grim tendon
#

oh god, WrapInClasses is recursive

#

yeah you really don't need that you could just map the tuple

sour coyoteBOT
#
that_guy977#0

Preview:ts ... [I in keyof T]: ComponentClass<T[I], unknown[] ...

grim tendon
#

you won't get the proper constructor typings here though

#

you could just start with the classes

sour coyoteBOT
#
that_guy977#0

Preview:```ts
...
const createView = <
T extends (new (...args: never[]) => unknown)[]

(
...args: T
): {[I in keyof T]: InstanceType<T[I]>} => {
// Do not care about the internals for no
...```

past swan
#

Yeah I just flipped it around and seems to be working

#
type WrapInInstances<T extends ComponentClass<any>[]> = T extends [infer R extends ComponentClass<any>, ...infer U extends ComponentClass<any>[]] ? [InstanceType<R>, ...WrapInInstances<U>] : []
#

So, this is the same as doing the recursive generic:

{[I in keyof T]: InstanceType<T[I]>}
grim tendon
#

i have no idea what you're trying to do with the recursive generic tbh

#

but seems like yes

#

it's just a mapped type