Аргумент типа «неизвестно» не может быть присвоен параметру типа «строка». TS2345

#javascript #reactjs #typescript #jsx

Вопрос:

Я запускаю этот код и только что увидел, как появилась эта ошибка.

 import { ethers } from 'ethers'
import { getMulticallContract } from 'utils/contractHelpers'
import { MultiCallResponse } from './types'

export interface Call {
  address: string // Address of the contract
  name: string // Function name on the contract (example: balanceOf)
  params?: any[] // Function params
}

interface MulticallOptions {
  requireSuccess?: boolean
}

const multicall = async <T = any>(abi: any[], calls: Call[]): Promise<T> => {
  try {
    const multi = getMulticallContract()
    const itf = new ethers.utils.Interface(abi)

    const calldata = calls.map((call) => [call.address.toLowerCase(), itf.encodeFunctionData(call.name, call.params)])
    const { returnData } = await multi.aggregate(calldata)

    const res = returnData.map((call, i) => itf.decodeFunctionResult(calls[i].name, call))
    

    return res
  } catch (error) {
    throw new Error(error)
  }
}
 

Это ошибка, которую я получаю, хотя до сих пор это работало просто отлично.

 Argument of type 'unknown' is not assignable to parameter of type 'string'.  TS2345

    28 |     return res
    29 |   } catch (error) {
  > 30 |     throw new Error(error)
       |                     ^
    31 |   }
    32 | }
    33 |
 

Я просмотрел связанные с этим вопросы, но не вижу точного решения в этом случае, но в настоящее время я изучаю машинопись.

Комментарии:

1. Что делать, если вы просто «выдадите ошибку» вместо «выдадите новую ошибку(ошибку)»

2. В чем именно заключается смысл этого catch пункта? Какого рода error вы ожидаете от кода в try блоке?

Ответ №1:

В подобном случае вы никогда не узнаете, какой тип ошибки будет выдан( unknown ), и new Error() получите строку

Основываясь на контексте вашей multicall функции, я бы посоветовал вам поместить значимую строку в эту ошибку (что обычно делают веб-сайты производственного уровня).

Вы бы бросили что-то вроде этого:

 const multicall = async <T = any>(abi: any[], calls: Call[]): Promise<T> => {
  try {
    const multi = getMulticallContract();
    const itf = new ethers.utils.Interface(abi);

    const calldata = calls.map((call) => [
      call.address.toLowerCase(),
      itf.encodeFunctionData(call.name, call.params),
    ]);
    const { returnData } = await multi.aggregate(calldata);

    const res = returnData.map((call, i) => itf.decodeFunctionResult(calls[i].name, call));

    return res;
  } catch {
    throw new Error('something went wrong in the multical function');
  }
};
 

Ответ №2:

В конце концов я просто добавил "useUnknownInCatchVariables": false, в tsconfig, и это предотвратило преобразование ошибок в неизвестные, что и стало причиной этой проблемы.

Я думаю, что мне также нужно обновить typescript, потому что в tsconfig есть предупреждение об этом флаге Unknown compiler option 'useUnknownInCatchVariables'.

Также обратите внимание, что в документах упоминается другое решение этой проблемы: https://www.typescriptlang.org/tsconfig#useUnknownInCatchVariables

 try {
  // ...
} catch (err) {
  // We have to verify err is an
  // error before using it as one.
  if (err instanceof Error) {
    console.log(err.message);
  }
}
 

Комментарии:

1. Вам действительно не следует отключать проверку, а лучше исправить свой код. Возможно, если Error был выдан экземпляр, ваш вызов new Error(error) был прерван.

2. Вы читали это: typescriptlang.org/tsconfig#useUnknownInCatchVariables Первая строка.. В TypeScript 4.0 была добавлена поддержка, позволяющая изменять тип переменной в предложении catch с любого на неизвестный. Тип переменной изменился, до этого вызов ошибки работал просто отлично.

3. Нет, код не сработал. Да, компилятор не жаловался и теперь жалуется, но передача Error экземпляра в качестве аргумента new Error является неправильной независимо от того, какую версию Typescript вы используете.