Push массива несмотря на объявление: TS2345: Аргумент типа 'string' не может быть назначен параметру типа 'never' - PullRequest
0 голосов
/ 20 июня 2019

У меня есть ошибка, указанная в заголовке для строки transactionIds: acc.transactionIds.push(currId).

Мой код выглядит так:

const resultObject: {
        amountAccumulated: number;
        amountLeft: number;
        rate: number | undefined;
        transactionIds: string[];
    } = arrDocs.reduce(
        (acc, curr, i) => {
            let currData:
                | admin.firestore.DocumentData
                | undefined = curr.data();
            if (currData === undefined) return acc;

            let currId = curr.id;
            let amountLeft: number = acc.amountLeft;
            let amountToAdd: number = Math.min(
                currData.remaining_amount,
                amountLeft
            );

            return {
                amountAccumulated: acc.amountAccumulated + amountToAdd,
                amountLeft: acc.amountLeft - amountToAdd,
                rate: undefined,
                transactionIds: acc.transactionIds.push(currId)
            };
        },
        {
            amountAccumulated: 0,
            amountLeft: spentAmount.amount,
            rate: undefined,
            transactionIds: []
        }
    );

Я не знаю, почему у меня ошибка. Кто-нибудь с идеей? Я прочитал в Интернете, что я должен просто объявить массив (что, как я думал, я сделал с объявлением resultObject).

Edit: Когда я внедряю предложенное изменение, используя оператор распространения, я получаю следующую ошибку:

TS2345: Argument of type '(acc: { amountAccumulated: number; amountLeft: number; rate: undefined; transactionIds: never[]; ...' is not assignable to parameter of type '(previousValue: { amountAccumulated: number; amountLeft: number; rate: undefined; transactionIds:...'.
      Type '{ amountAccumulated: number; amountLeft: number; rate: undefined; transactionIds: string[]; }' is not assignable to type '{ amountAccumulated: number; amountLeft: number; rate: undefined; transactionIds: never[]; }'.
        Types of property 'transactionIds' are incompatible.
          Type 'string[]' is not assignable to type 'never[]'.
            Type 'string' is not assignable to type 'never'.

Вот код:

return {
     amountAccumulated: acc.amountAccumulated + amountToAdd,
     amountLeft: acc.amountLeft - amountToAdd,
     rate: undefined,
     transactionIds: [...acc.transactionIds, currId]
 };

1 Ответ

2 голосов
/ 20 июня 2019

Я не могу объяснить, почему ошибка говорит именно то, что говорит, но эта строка неверна. push возвращает число, а не массив, но transactionIds должен быть массивом.

Если вы хотите каждый раз создавать новый объект, вы можете разложить существующие идентификаторы транзакций и добавить новый, например:

transactionIds: [...acc.transactionIds, currId]

Вы сказали, что у вас проблемы с тем, чтобы заставить это работать, и что TypeScript все еще жалуется на массив never[]. Поскольку вам требуется, чтобы TypeScript выводил тип аккумулятора transactionIds, я полагаю, что это неверный вывод.

Я бы определил тип:

interface ResultType {
    amountAccumulated: number;
    amountLeft: number;
    rate: number | undefined;
    transactionIds: string[];
}

и затем используйте его на объекте, который вы предоставляете для аккумулятора, чтобы TypeScript было ясно, какой тип transactionIds:

const resultObject: ResultType = arrDocs.reduce(
    (acc, curr, i) => {
        // ...
    },
    <ResultType>{
        amountAccumulated: 0,
        amountLeft: spentAmount.amount,
        rate: undefined,
        transactionIds: []
    }
);

Как примечание: использование reduce для этого ничего не делает, а только усложняет. У вас также есть много избыточных аннотаций типов, которые TypeScript будет совершенно счастлив вывести (правильно). Вот как я к этому подхожу:

Во-первых, у меня был бы тип (хотя, если вы предпочитаете не делать этого, вам не обязательно):

interface ResultType {
    amountAccumulated: number;
    amountLeft: number;
    transactionIds: string[];
    rate: number | undefined;
}

Тогда я бы сделал это так:

let amountAccumulated = 0;
let amountLeft = 0;
let transactionIds: string[] = [];
for (const curr of arrDocs) {
    let currData = curr.data();
    if (currData !== undefined) {
        let amountToAdd = Math.min(
            currData.remaining_amount,
            acc.amountLeft
        );
        amountAccumulated += amountToAdd;
        amountLeft -= amountToAdd;
        transactionIds.push(curr.id);
    }
}
const resultObject: ResultType = {
    amountAccumulated,
    amountLeft,
    rate: undefined,
    transactionIds
};

Если вы не хотите иметь тип, просто замените его в последнем выражении, создающем объект:

const resultObject: {
    amountAccumulated: number;
    amountLeft: number;
    transactionIds: string[];
    rate: number | undefined;
} = {
    amountAccumulated,
    amountLeft,
    rate: undefined,
    transactionIds
};
...