Функция ограничения по трубе - PullRequest
1 голос
/ 12 марта 2020

Цель состоит в том, чтобы создать функцию Pipe, которая ограничивает Piping менее производным типом, чем первоначально заданный (Contravariance), используя как можно меньше деклараций типа.

Кажется, что можно создать такой Pipe. Сценарий ниже.

  interface Task<A> {
    (): Promise<A>;
  }

  declare const initialValue: Task<boolean>;
  declare const firstLine: (ma: Task<boolean>) => Task<void>;
  declare const secondLine: (ma: Task<void>) => Task<void>; // working
  declare const secondLineProblem: () => Task<void>; // compilation error

  type PipedFunc<ExpectedType, AtualType, Result> = ((
    a: AtualType
  ) => Result) extends (b: any) => any
    ? AtualType extends ExpectedType
      ? (b: AtualType) => Result
      : [
          "Function does not match the expected signature: ",
          (b: ExpectedType) => Result
        ]
    : never;

  type Pipe = {
    <A>(a: A): A;
    <A, B>(a: A, ab: (a: A) => B): B;
    <A, B, BArg, C>(a: A, ab: (a: A) => B, bc: PipedFunc<B, BArg, C>): C;
    <A, B, BArg, C, CArg, D>(a: A, ab: (a: A) => B, bc: PipedFunc<B, BArg, C>, cd: PipedFunc<C, CArg, D>): D;
  };

  export const pipe: Pipe = function(
    a: unknown,
    ab?: Function,
    bc?: Function,
    cd?: Function,
  ): unknown {
    switch (arguments.length) {
      case 1:
        return a;
      case 2:
        return ab!(a);
      case 3:
        return bc!(ab!(a));
      case 4:
        return cd!(bc!(ab!(a)));
    }
    return;
  };

  let task01 = pipe(initialValue, firstLine, secondLine, secondLine);
  let task02 = pipe(initialValue, firstLine, secondLine, secondLineProblem); // Expected compilation Error
  //                                                     ↑
  // Compilation Error - Argument of type '() => Task<void>' is not assignable to parameter of type
  //'["Function does not match the expected signature: ", (b: Task<void>) => Task<void>]'.ts(2345)

Но этот подход делает необходимым использование o Декларации типа.

  let sum00 = pipe(10, firstValue => firstValue + 1, (secondValue: number) => secondValue); // works

Цель состоит в том, чтобы найти подход, который выводит тип для аргумента секунд ниже , Без использования объявления типов.

  let sum00 = pipe(10, firstValue => firstValue + 1, secondValue => secondValue); // does not work
  //                                                 ↑
  // Compilation Error - Parameter 'value' implicitly has an 'any' type.ts(7006)

Возможно ли это? Он думал об использовании какого-либо условного типа для вывода Типа SecondValue, но не было возможности найти какой-то правильный пример.

Существуют ли способы придумать это решение в TypeScript?

...