This is great and all, but what if we want the chain to be able to accept multiple types?
That is, we wrap TypeA, then transform to TypeB, and we want to continue the chain from there?
Generally, I recommend to keep the ValueT static in the Chain, and instead use something like a PropertySheet which allows for a value to be multiple, pre-defined data types.
This will allow us to remain 100% type-checked, since the metadata transform will know its input type is a PropertySheet. Otherwise the type of ValueT is unknown at the time of metadata transformation.
If you use a PropertySheet, that means that some transformations which assume a PropertySheet to have a certain value as a certain type can fail.
In this case, though, it's better to just use Options to chain those failable transformations. So the transformation type would be:
transform: (v: PropertySheet) => Option<PropertySheet>
Then in our apply function, when we compute the next value in the chain, if the Option is empty we just pass along the empty Option as the value.
Thus, by the end of the Chain, we just end up with an empty Option, so we know one of the operations failed.
We could also use a Result monad instead if we would like to include an error message, meaning the transform would be of type:
transform: (v: PropertySheet) => Result<PropertySheet>
And while this is a good pattern, if we know that no transform can produce an error, there is no use for metadata, or you just really want to have transforms between types, then we can adapt the Chain type to allow for a separate transformation return type (essentially allowing us to change the Chain's ValueT after a transformation).