I need to define a schema of "operations" to be used on my application. This schema should be extendable for other groups of "operations". It should contain a dictionary of settings for each keyword.
At some point, a "generic caller" should receive the type of the "operation" plus the keyword and make a cache of it for later calls.
I also need this "generic caller" to ensure the requested keyword is defined on the operation at compile time, so it shows errors to the developers on VS Code.
Below, a solution that's very close to what I need:
// Operation interface
interface Operation {
url: string
parameters: Record<string,string>
}
// Operations schema
class Operations {}
class BaseOperations extends Operations {
one: {
url: '/one',
parameters: {p: '1'}
}
two: {
url: '/two',
parameters: {}
}
}
// Generic caller (which caches the calls)
function runOperation<T extends Operations>(type: {new(): T;}, keyword: keyof T) {
let operation = new type();
//cache_and_run(operation[keyword]);
}
// Main
function main() {
runOperation(BaseOperations, 'one');
runOperation(BaseOperations, 'two');
runOperation(BaseOperations, 'three'); // VS Code error, as expected
}
The only problem here is that the parameters defined in Operations are not bound the Operation interface. It's a minor issue, however I'd like to be able to make sure both ends (operations definitions and their uses) are checked at compile time.
After some research, I've found the "index signature" parameter, which allows for enforcing the returned type:
class BaseOperations extends Operations {
[x:string]: Operation
one: {
url: '/one',
parameters: {p: '1'}
}
two: { // 'uarl' is not assignable
uarl: '/two'
}
}
However, this approach disabled the 'one'|'two' check happening on runOperation, since any string is now a valid keyof BaseOperations.
Any suggestions?