Сначала давайте определим класс Transformer
.
class Transformation<T> {
constructor(readonly value: T) {
this.value = value;
}
public static from<U>(input: U): Transformation<U> {
return new Transformation(input);
}
public step<U>(transformer: Transformer<T, U>): Transformation<U> {
return new Transformation(transformer.run(this.value));
}
}
Он использует интерфейс Transformer
. Мы можем определить его как:
interface Transformer<T, U> {
run(input: T): U;
}
При наличии этого преобразования гарантированно будут правильными во время компиляции.
Transformation.from("This is a long story")
.step(new Uppercase())
.step(new Truncate()); // OK
Transformation.from("This is a long story")
.step(new Uppercase())
.step(new SquareRoot()); // Compile-time error: Type 'string' is not assignable to type 'number'.ts(2345)
Обновление
Примечание: в вашем примере вы передаете конструкторы из Uppercase
и Truncate
в качестве step
s. В моем решении вместо них используются экземпляры . Если вместо этого вы настаиваете на передаче конструкторов, вам нужно будет сделать метод run
stati c.
class Uppercase {
public static run(str: string): string {
return str.toUpperCase();
}
}
class Truncate {
public static run(str: string): string {
return str.substr(0, 10) + '...';
}
}
class SquareRoot {
public static run(num: number): number {
return Math.sqrt(num);
}
}
Transformation.from("This is a long story")
.step(Uppercase)
.step(Truncate);
Transformation.from("This is a long story")
.step(Uppercase)
.step(SquareRoot); // Compile-time error: Type 'string' is not assignable to type 'number'.ts(2345)