-
-
Save Snugug/72a6181e6b641d9e32df126135c0ae0c to your computer and use it in GitHub Desktop.
import { validate, IsInt, IsEmail, IsIn, IsNotEmpty } from 'class-validator'; | |
import { Provider } from './provider'; | |
export class InstanceConfig { | |
[key:string]: number | string; | |
@IsEmail() | |
@IsNotEmpty() | |
email: string; | |
@IsInt() | |
@IsNotEmpty() | |
duration: number; | |
} | |
export class InstanceInstance { | |
[key:string]: number | string | boolean; | |
@IsNotEmpty() | |
template: string; | |
@IsNotEmpty() | |
@IsIn(['emea', 'us-central', 'apac', 'aus-sydney']) | |
region: string; | |
@IsNotEmpty() | |
@IsIn(['default', 'on', 'off']) | |
internetAccess: string; | |
@IsNotEmpty() | |
smartrdp: boolean; | |
@IsNotEmpty() | |
@IsInt() | |
idleRuntimeLimit: number; | |
@IsNotEmpty() | |
@IsIn(['shutdown', 'off', 'suspend']) | |
idleRuntimeType: string; | |
@IsNotEmpty() | |
@IsInt() | |
totalRuntimeLimit: number; | |
} | |
export class InstanceProvider implements Provider<InstanceConfig, InstanceInstance> { | |
Config: new() => InstanceConfig; | |
Instance: new() => InstanceInstance; | |
} |
export interface Provider<ProviderConfig, ProviderInstance> { | |
Config: new () => ProviderConfig; | |
Instance: new () => ProviderInstance; | |
} |
import { InstanceProvider, InstanceConfig, InstanceInstance } from './skytap'; | |
import { Provider } from './provider'; | |
import { validate } from 'class-validator'; | |
async function foo<ProviderConfig, ProviderInstance>(provider: Provider<ProviderConfig, ProviderInstance>) { | |
const config = new provider.Config(); | |
config.email = 'foogmail.com'; | |
config.duration = 10; | |
let errs = await validate(config, {whitelist: true}); | |
console.log(errs); | |
} | |
foo<InstanceConfig, InstanceInstance>(new InstanceProvider()); |
Thanks @chriseppstein, I'm very close, but I'm missing something and I don't quite understand what's missing. With the above (updated) code, I get the following compile errors:
Property 'email' does not exist on type 'ProviderConfig'.
Property 'duration' does not exist on type 'ProviderConfig'.
I seem to be passing everything through properly, and the type validation is now working as I expect, but the actual InstanceConfig
class doesn't appear to be used for validation, so it won't let me set the properties as I expect I should be able to.
Thoughts on this last bit? Thanks!
I think I've narrowed it down to https://gist.github.com/Snugug/72a6181e6b641d9e32df126135c0ae0c#file-use-js-L5, specifically that even though I believe I'm passing the types in properly for the generic, it's not actually picking up the structure inside the function. I can confirm that this in general works because if I use InstanceProvider
outside of the function call it all works as expected
While that doesn't work, InstanceProvider.Config
is not a constructor so I can't new
it
I don't particularly understand the difference between the
Config
and theInstance
classes. They appear to be the same. But generally, this appears to be a factory pattern and there's a few ways to accomplish this in TypeScript.You need an interface for a provider factory. If you can enumerate all possible providers in your codebase at build time, it's generally easier and better. If you need your factory to be extensible by code at runtime from outside of this library, it's a little trickier.
The main thing you probably need to know about is how to define an interface to a constructor method. Read the section on
Class Types
in the typescript handbook for interfaces. Another example is hereOnce you see how that works, I suspect that you can arrive at either having each provider also export a factory class such as:
Or you may also note that given the interface:
that when you
import * as provider1 from "./provider1.ts"
, theprovider1
constant implements the interfaceProvider<provider1.Config, provider1.Instance>
and the interface ofprovider1
is accessible as a type viatypeof provider1
.