#Array of abstract classes

38 messages · Page 1 of 1 (latest)

crisp dagger
#

I'm trying to create a function that has a parameter thats an array of abstract classes and options to pass to their constructor:

class Provider<Options extends Record<string, unknown> = Record<string, unknown>> {
  constructor(public readonly options: Options) {}
}

class ADF {
  static create<Values extends Record<string, unknown>, P extends Provider>(providers?: [ProviderClass<P, P['options']>, P['options']][]) {
    const adf = new ADF();
    providers.forEach(([ClassName, options]) => {
      adf.providers.push(new ClassName(options));
    })
    return adf;
  }
}

I'm trying to use it like so:

const adf = ADF.create([
    [FirstExampleProvider, { foo: 'bar' }],
    [SecondExampleProvider, { bar: 'baz' }],
]);

The issue i'm having here is that any providers after the first one get compilation errors:

TS2322: Type 'typeof SecondExampleProvider' is not assignable to type 'ProviderClass<FirstExampleProvider, FirstExampleConfigValues>'.   Types of construct signatures are incompatible.     Type 'new (configuration: Configuration<SecondExampleConfigValues>, environment: EnvironmentProvider | undefined, options?: SecondExampleConfigValues) => SecondExampleProvider' is not assignable to type 'new (configuration: Configuration<FirstExampleConfigValues>, environment: EnvironmentProvider | undefined, options: FirstExampleConfigValues) => FirstExampleProvider'.       Types of parameters 'configuration' and 'configuration' are incompatible.         Type 'Configuration<FirstExampleConfigValues>' is not assignable to type 'Configuration<SecondExampleConfigValues>'.           Property 'bar' is missing in type 'FirstExampleConfigValues' but required in type 'SecondExampleConfigValues'.

// And

TS2322: Type '{ bar: string; }' is not assignable to type 'FirstExampleConfigValues'.   Object literal may only specify known properties, and 'bar' does not exist in type 'FirstExampleConfigValues'.

Playground Link: https://www.typescriptlang.org/play?#code/MYGwhgzhAEAKBOB7AbgSwCYFN4B4DyADgC6qIB2MmAHkZmejAEqbCLzo4RHypkDmAGmgBXMgGsyiAO5kAfNAC80Zq3aduvQSPGSZs+QG8AUNGisK3YcCJsAFAWEAjEKmDR4mMOnIgAntERiUgoALmhCEnIIAEpoAwBfI0SjIl8CTGgAMVR4LgBRKjAAWwIQTABhcgAzVD4ANTAQYUwYJQNoKsREMK4efmh4gG4jI1BIGGzcogLi0swEFAxsaGpaehgFtCxcSfzCkrLKshr6xuaIQ2TU9OgAZRZydBmDiurahqaWxTjoRzB4HoafpDEZjKB3B70Z5zTZLeArGh0BhwJBbbA4e7mJ77OZHE4fc6XEbXDKw7blcBQHAAFQRa2RZOwQgiwUoiPW0GpAG0AOSBSIUHkAXXkSjImCk0Fs-NZYRZUViCnk1OGoMpMAAggARTJxEymaAOZyuQ2ouEQMIqNgcXqaISM+CiuIg-WmI0uNxcMAkNzADzezA4AlfVZIpgPNS2-hCUQSaRye10sMoxbbINnFr6exm7YQAD8YS5Dop4xwsHtvJlUWFsgrfKC1aFQq5QtixgNHbMUSI0C8VW+4sl2sytmiw07BoIOew+YAdJ14HkwMAABa2WxcktQAByxUwQirFFbinkfdnXnQDtsW4gu6K+4CDYo0THrs7HiIwngZF76Cq44NRIAEg33dE0LwdMskw5B1mWghlKyfCAa1sIwgKAikLRTNF4BvMtmVrNCgMPLC8G+BJexgPA0OiMIiBXVAYGMdD6MY2cp1TGdNxACBZzIPchQHCVoEw6UkNfIiPy-H9WIgYYgMSZJzC4X9+yUYdZz9TxaA3N8uV2aYcTKWCfk6bpoB5P54B5AYhQEPTMUeaFjOneAhHaKywkssAAC8bPiOyjFbQYgA

viral quiver
#

what's ProviderClass?

crisp dagger
#
type ProviderClass<T extends Provider, Options extends T['options']> = new (options: Options) => T;
viral quiver
#

oh i think the issue might be that each tuple in the array doesn't have a separate generic link

#

why not use typeof to get the classes directly though?

#

why go through ProviderClass?

crisp dagger
#

What would that look like?

viral quiver
#

P extends typeof Provider maybe

wait idk if that would work with inheritance though one sec-

#

ok yeah looks like that works

crisp dagger
#

that breaks the P['options'] though

#

Also doesn't let me pass in the class anymore

viral quiver
#

hold on can you put your stuff in a playground

silk drumBOT
#
CryptikLemur#0001

Preview:```ts
class Provider<
Options extends Record<string, unknown> = Record<
string,
unknown

{
constructor(public readonly options: Options) {}
}

type FirstExampleConfigValues = {foo: string}

class FirstExampleProvider extends Provider<FirstExampleConfigValues> {}
...```

viral quiver
#

wait, why do you even need to pass your class and options separately?

crisp dagger
#

technically im doing more in my actual example,. but i simplified it

#

the providers have more in their constructor

#

that the consumer isnt aware of

viral quiver
#

hmm, not sure if this is useful to your actual example then, but;
why not just utilize OOP?

crisp dagger
#

can you elaborate

silk drumBOT
#
CryptikLemur#0001

Preview:```ts
class Configuration {}

class Provider<
Options extends Record<string, unknown> = Record<
string,
unknown

{
constructor(
public readonly configuration: Configuration,
public readonly options: Options
) {}
}

type FirstExampleConfigValues = {foo: string}
...```

crisp dagger
#

updated the example

silk drumBOT
#
That_Guy977#5882

Preview:```ts
class Provider {
constructor(
public readonly options: Record<string, unknown>
) {}
}

class FirstExampleProvider extends Provider {
constructor(options: {foo: string}) {
super(options)
}
}

class SecondExampleProvider extends Provider {
constructor(options: {bar: string})
...```

viral quiver
#

this is pretty much a rewrite, but it utilizes OOP a bit more

crisp dagger
#

my updated example shows why i dont do that

viral quiver
#

to pass the config, right

crisp dagger
#

The providers themselves arent aware of the ADF configuration property

#

trying to avoid making that visible, and forcing the consumer to pass it in to every provider they want to add

viral quiver
#

would setting the config after constructor make sense in the context of whatever this is being used in?

#

if so you could have the ADF set the config itself

crisp dagger
#

i mean, i could

viral quiver
#

and that would lean into OOP quite a lot, lol

crisp dagger
#

but thats also a little less than ideal

#

as the type is possibly undefined

viral quiver
#

aight understandable

crisp dagger
#

so everything in the providers calling configuration would have to nullish call it or typeguard it. I also cant readonly it

viral quiver
crisp dagger
#

Is that solvable...?

viral quiver
#

don't think so