I have a unique class method called continue()
. This method takes a callback and returns the same type of value as the given callback. Here's an example:
function continue<T>(callback: () => T): T {
// ...
}
Now, I'm creating a class that is parameterized over the result type of the continue()
function which we'll call Semantic
. My continue()
method in this class will pass along the result to the callback:
class Checkpoint<Semantic> {
function continue<T>(callback: (val: Semantic) => T): T {
// ...
}
}
This Semantic
type can be one of a few possible types, and I need to differentiate behavior at runtime based on the type of Checkpoint
being used:
type runtimeDiscriminator = 'Script' | 'Statement'
class Checkpoint<Semantic> {
type: runtimeDiscriminator
constructor(blah: any, type: runtimeDiscriminator) {
// ...
this.type = type
}
continue<T>(callback: (val: Semantic) => T): T {
if (this.type === 'Script') { /* ... do things */ }
else { /* ... do other things */ }
}
}
The challenge I'm facing is trying to incorporate this information into the type-system and using user-defined type guards to ensure proper typing throughout the process.
type runtimeDiscriminator = 'Script' | 'Statement'
class Checkpoint<Semantic> {
type: runtimeDiscriminator
constructor(blah: any, type: 'Script'): Checkpoint<Script>
constructor(blah: any, type: 'Statement'): Checkpoint<Statement>
constructor(blah: any, type: runtimeDiscriminator) {
// ...
this.type = type
}
producesScript(): this is Checkpoint<Script> {
return this.type === 'Script'
}
producesStatement(): this is Checkpoint<Statement> {
return this.type === 'Statement'
}
continue<T>(callback: (val: Semantic) => T): T {
// ... perform runtime checks and narrow down the resultant type from `callback`
}
}
However, I encountered an error from the typechecker:
Type annotation cannot appear on a constructor declaration. ts(1093)
I'm puzzled by this restriction and unsure how to proceed without duplicating annotations at every callsite. How can I properly overload constructors like this?
Edit: Hopefully, I haven't mixed up TypeScript terminology too much. Coming from OCaml background, the C++-like terms in TypeScript can sometimes get confusing!