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?