I'm trying to build a graphical programming editor, similar to Max, Grasshopper, or Antimony using TypeScript.
The basic idea is that a block represents a function with inputs on the left and outputs on the right and you can connect inputs and outputs together with edges.
The challenge I'm facing right now is that I want to have a type-safe static definition of a block along with some runtime type introspection to prevent the user from connecting inputs and outputs with types that don't match.
The simplest place to start is just defining a block as a function. For example:
function AdditionBlock(x: number, y: number): number {
return x + y
}
However, there are some problems with this approach.
- How do I generate the labels for each input/output on the block?
- How can I validate at runtime that the user is attaching the proper type to one of the inputs of this block?
I've tried refined this approach a little bit, but I haven't quite been able to pull it off:
I created my own aliases to the intrinsic type system so that I can use instanceof
at runtime.
class IntrinsicType<ActualType> {}
const NumberType = new IntrinsicType<number>()
const StringType = new IntrinsicType<string>()
Then I created a class with static properties defining the inputs, outputs, and evaluate function:
class AdditionBlock {
static inputs: [
{ name: "x"; type: NumberType },
{ name: "y"; type: NumberType }
]
static outputs: [{ name: "sum"; type: NumberType }]
static evaluate(x: number, y: number): number {
return x + y
}
}
But already, I'm not terribly happy how I haven't been able connect the input and output types with the evaluate definition.
I think what would pretty much solve my problem is if there was some way to introspect the type definition of a function at runtime even if it were as simple as checking for the instanceof
a class.
I hope that all makes sense -- please let me know if I should clarify anything.