I have a notion of a Step, which requires value of type A as an input and gives out a value of type B.
class Step<A, B> {
constructor(private readonly f: (a: A) => B) { }
public run(a: A): B {
return this.f(a);
}
}
Now I would like to compose two steps, so I end up with something like this inside class Step:
public andThen<C, D>(nextStep: Step<C, D>): Step<A, D> {
return new Step<A, D>((state: A) => {
const b: B = this.f(state);
return nextStep.run(b); // <---- compile error, B and C have no relation defined
});
}
What I would like to achieve is to somehow tell the type system that we can pass type B to a function which expects type C (structural typing should check that all fields in C are present in B), so that the line return nextStep.run(b) works fine.
Example:
const stepA: Step<{}, {a: number, b: string}> = new Step((input: {}) => ({ a: 5, b: "five" }));
const stepB: Step<{a: number}, {c: number}> = new Step((input: {a: number}) => ({c: input.a + 5}));
const steps = stepA.andThen(stepB)
As you can see stepB requires as an input {a: number}, so it can be fed an output from stepA which is {a: number, b: string}. But I cannot figure out how to define the relation in andThen. Any thoughts how this can be achieved?
The core point is
SubTypetype:It says that if the type extends given type then its ok, but its not then never. Pay attention how it is used:
So we are saying that if type
BextendsC, soBis more specific type thenCthen we allow on that, if not we don't bynever. Additionally we allow onBitself (without union there was still compilation error)