Использование вами обобщений немного сбивает меня с толку, так как не похоже, что вы прояснили разницу между параметром типа переменные и конкретными типами, которые вы подключаете к ним.Не говоря уже о том, что вы используете не-TS термины, такие как val
и None
.В любом случае, следующее - это то, что компилируется, и может дать вам то поведение, которое вы ищете:
type NotNever<T, Y=T, N=never> = [T] extends [never] ? N : Y;
// just create types, don't worry about implementation
declare class BaseComponent<In, Out, Xin=never, Xout=never> {
// make BaseComponent depend structurally on type parameters
i: In;
o: Out;
xi: Xin;
xo: Xout;
// andThen() is generic, and only accepts the right kind of other component
// only callable if Xin and Xout are *not* never
andThen<Yin, Yout>(
this: NotNever<Xin | Xout, this>,
c: BaseComponent<Xin, Xout, Yin, Yout>
): BaseComponent<In, Out, Yin, Yout>;
// run() is only callable if Xin and Xout *are* never
run(this: BaseComponent<In, Out, never, never>): void;
}
// create some concrete subclasses where parameters are set with string literal types
class Component1 extends BaseComponent<'In', 'Out', 'Xin', 'Xout'> { }
class Component2 extends BaseComponent<'Xin', 'Xout', 'Yin', 'Yout'> { }
class Component3 extends BaseComponent<'Yin', 'Yout'> { }
Вы можете увидеть, как это работает:
const c1 = new Component1();
const c2 = new Component2();
const c3 = new Component3();
c1.andThen(c1); // error
c1.andThen(c2); // okay
c1.andThen(c3); // error
c1.run(); // error
c2.andThen(c1); // error
c2.andThen(c2); // error
c2.andThen(c3); // okay
c2.run(); // error
c3.andThen(c1); // error
c3.andThen(c2); // error
c3.andThen(c3); // error
c3.run(); // okay
const chain = c1.andThen(c2).andThen(c3) // BaseComponent<'In', 'Out', never, never>;
chain.run(); // okay
Я думаю, это похоже на то, что вы хотите?Надеюсь, это поможет;удачи!
РЕДАКТИРОВАТЬ: Еще один способ сделать то же самое, но не беспокоясь о условные типы и полиморфные this
заключается в следующем:
// one base class for the end of the chain
declare class EndComponent<In, Out> {
i: In;
o: Out;
run(): void;
}
// another base class for intermediate parts of the chain
declare class PipeComponent<In, Out, Xin, Xout> {
i: In;
o: Out;
xi: Xin;
xo: Xout;
// andThen() is overloaded
andThen<Yin, Yout>(
c: PipeComponent<Xin, Xout, Yin, Yout>
): PipeComponent<In, Out, Yin, Yout>;
andThen(c: EndComponent<Xin, Xout>): EndComponent<In, Out>;
}
class Component1 extends PipeComponent<'In', 'Out', 'Xin', 'Xout'> { }
class Component2 extends PipeComponent<'Xin', 'Xout', 'Yin', 'Yout'> { }
class Component3 extends EndComponent<'Yin', 'Yout'> { }
Остальные должны вести себя как прежде.Еще раз удачи!