Цепочка функций в TypeScript с типами Omit - PullRequest
0 голосов
/ 12 декабря 2018

Допустим, я хотел реализовать цепочку типизированных функций в TypeScript, но в этом случае вызов функции удаляет эту функцию из возвращаемого типа.Например:

type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;

interface Chainable {
  execute: () => Promise<void>;
}

interface Chain1 extends Chainable {
  chain1?: () => Omit<this, 'chain1'>;
}

interface Chain2 extends Chainable {
  chain2?: () => Omit<this, 'chain2'>;
}

let chain: Chain1 & Chain2 = {
  execute: () => null,
  chain1: () => {
    delete chain.chain1;
    return chain;
  },
  chain2: () => {
    delete chain.chain2;
    return chain;
  }
};

chain.chain1().chain2().execute(); // Using the function chain

Когда я вызываю chain.chain1(), я получу Pick<Chain1 & Chain2, "execute" | "chain2" в качестве возвращаемого типа, и это здорово, поскольку он не позволяет мне дважды вызывать chain1.

Однако, как только я связываю его с помощью функции chain2, тип возвращаемого значения становится Pick<Chain1 & Chain2, "chain1" | "execute".Это позволило бы мне снова позвонить chain1, что я и пытаюсь предотвратить.В идеале компилятор будет жаловаться, что Property 'chain1' does not exist on type:

chain.chain1().chain2().chain1(); // I want this to return a compiler error :(

Правильно ли я поступаю?Возможно ли в TypeScript постепенно объединять несколько типов Omit вместе, чтобы возвращаемые типы постоянно опускали свойства?

1 Ответ

0 голосов
/ 12 декабря 2018

Я думаю, что тип для this определяется, когда функция сначала проверяется, а затем не переоценивается в любой момент после.Таким образом, this для второго вызова chain2 все равно будет исходным this, а не типом возврата chain1.Я не уверен, является ли это предполагаемым поведением или ошибкой, возможно, вы захотите проверить GitHub на наличие подобных проблем.

Один из способов - захватить this для любой данной функции, используя параметр общего типа, который будетпривязан к this.Это обеспечит правильное прохождение типа через функциональную цепочку.Одна небольшая проблема заключается в том, что при использовании функции со стрелкой набор не будет работать, вам нужно будет использовать обычные функции и получить доступ к this:

type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;

interface Chainable {
    execute: () => Promise<void>;
}

interface Chain1 extends Chainable {
    chain1?: <T extends Chain1>(this: T) => Omit<T, 'chain1'>;
}

interface Chain2 extends Chainable {
    chain2?: <T extends Chain2>(this: T) => Omit<T, 'chain2'>;
}

let chain: Chain1 & Chain2 = {
    execute: () => null,
    chain1: function () {
        delete this.chain1;
        return this;
    },
    chain2: function ()  {
        delete this.chain2;
        return this;
    }
};

chain.chain1().chain2().execute(); // Using the function chain
chain.chain1().chain2().chain1().execute(); // error
...