50

我有以下代码:

try {
  phpDoc(vscode.window.activeTextEditor);
} catch (err) {
  console.error(err);
  vscode.window.showErrorMessage(err.message);
}

但是err.message得到错误Object is of type 'unknown'.ts(2571)err.但我无法在中键入对象catch (err: Error)

我该怎么办?

4

4 回答 4

53

作为对CertainPerformance的补充回答

在 TypeScript 4.0 之前,catch子句绑定设置为any允许轻松访问message属性。这是不安全的,因为不能保证抛出的东西会从Error原型继承——碰巧我们除了错误之外什么都不抛出,作为最佳实践:

(() => {
    try {
        const myErr = { code: 42, reason: "the answer" };
        throw myErr; //don't do that in real life
    } catch(err) {
        console.log(err.message); //undefined
    }
})();

TypeScript 4.0引入了一个更安全的catch子句选项,允许您将参数注释为unknown,强制您执行显式类型断言,或者更好地进行类型保护(这使得子句在编译时和运行时都安全)。

但是,为了避免破坏大多数代码库,您必须明确选择加入新行为:

(() => {
    try {
        throw new Error("ouch!");
    } catch(err: unknown) {
        console.log(err.message); //Object is of type 'unknown'
    }
})();

TypeScript 4.4 引入了一个新的编译器选项,称为useUnknownInCatchVariables强制此行为。默认情况false下,但如果您strict打开了该选项(如您所愿),则它已打开,这很可能是您首先收到错误的原因。

于 2021-07-05T14:02:46.387 回答
27

如果您不想在升级 TypeScript 但处于严格模式后更改所有代码,则可以在覆盖它的选项之后添加以下编译器选项,正如Oleg 的回答strict中所暗示的那样:

tsconfig.json

{
  "compilerOptions": {
    [...]
    "strict": true,
    "useUnknownInCatchVariables": false,
    [...]
    },
  },
}

"strict": true,设置useUnknownInCatchVariables为 true,然后"useUnknownInCatchVariables": false,覆盖它并将其设置回 false。

于 2021-08-30T12:36:53.120 回答
24

这是因为可以抛出任何东西unknown,因此.

const fn = () => {
  throw 'foo';
};
try {
  fn();
} catch(e) {
  console.log(e);
  console.log(e instanceof Error);
  console.log(e === 'foo');
}

在访问该属性之前,您需要检查这err实际上是一个错误以缩小范围。message

try {
  phpDoc(vscode.window.activeTextEditor);
} catch (err) {
  console.error(err);
  if (err instanceof Error) {
    vscode.window.showErrorMessage(err.message);
  } else {
    // do something else with what was thrown, maybe?
    // vscode.window.showErrorMessage(String(err));
  }
}
于 2021-07-04T00:39:57.640 回答
0

我的TypeScript版本低于4.0,我无法让它再次工作,然后我创建了一个辅助函数来规范错误,如下所示:

interface INormalizedError {
  /**
   * Original error.
   */
  err: unknown;

  /**
   * Is error instance?
   */
  isError: boolean;

  /**
   * Error object.
   */
  error?: Error;

  /**
   * Call stack.
   */
  stack?: Error['stack'];

  /**
   * Error message.
   */
  message: string;

  toString(): string;
}

/**
 * Normalize error.
 *
 * @param err Error instance.
 * @returns Normalized error object.
 */
function normalizeError(err: unknown): Readonly<INormalizedError> {
  const result: INormalizedError = {
    err,
    message: '',
    isError: false,
    toString() {
      return this.message;
    }
  };

  if (err instanceof Error) {
    result.error = err;
    result.message = err.message;
    result.stack = err.stack;
    result.isError = true;
    result.toString = () => err.toString();
  } else if (typeof err === 'string') {
    result.error = new Error(err);
    result.message = err;
    result.stack = result.error.stack;
  } else {
    const aErr = err as any;

    if (typeof err === 'object') {
      result.message = aErr?.message ? aErr.message : String(aErr);
      result.toString = () => {
        const m = typeof err.toString === 'function' ? err.toString() : result.message;
        return (m === '[object Object]') ? result.message : m;
      };
    } else if (typeof err === 'function') {
      return normalizeError(err());
    } else {
      result.message = String(`[${typeof err}] ${aErr}`);
    }

    result.error = new Error(result.message);
    result.stack = aErr?.stack ? aErr.stack : result.error.stack;
  }

  return result;
}

一个使用示例:

try {
  phpDoc(vscode.window.activeTextEditor);
} catch (err) {
  const e = normalizeError(err);
  console.error(err);
  vscode.window.showErrorMessage(e.message);
}
于 2021-10-27T20:26:05.370 回答