catch 中的错误对象类型未知
Error object inside catch is of type unkown
我有以下代码:
try {
phpDoc(vscode.window.activeTextEditor);
} catch (err) {
console.error(err);
vscode.window.showErrorMessage(err.message);
}
但是 err.message
在 err.
上收到错误 Object is of type 'unknown'.ts(2571)
,但我无法在 catch (err: Error)
中键入对象。
我该怎么办?
因为任何东西都可以抛出,所以unknown
.
const fn = () => {
throw 'foo';
};
try {
fn();
} catch(e) {
console.log(e);
console.log(e instanceof Error);
console.log(e === 'foo');
}
在访问 message
属性.
之前,您需要检查 err
实际上是一个错误以缩小范围
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));
}
}
补充回答CertainPerformance's :
在 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 introduced 一个更安全的 catch
子句选项,允许您将参数注释为 unknown
,强制您进行显式类型断言,或者更好, 键入 guard(这使得该子句在编译时和运行时都是安全的)。
但是,为了避免破坏大部分代码库,您必须明确选择加入新行为:
(() => {
try {
throw new Error("ouch!");
} catch(err: unknown) {
console.log(err.message); //Object is of type 'unknown'
}
})();
TypeScript 4.4 引入了一个名为 useUnknownInCatchVariables
的新编译器选项,强制执行此行为。默认情况下它是 false
,但是如果你打开了 strict
选项(正如你应该的那样),它就会打开,这很可能是你首先得到错误的原因。
如果您不想在升级 TypeScript 后更改所有代码但处于严格模式,则可以在 strict
选项后添加以下编译器选项以覆盖它,如 :
tsconfig.json
{
"compilerOptions": {
[...]
"strict": true,
"useUnknownInCatchVariables": false,
[...]
},
},
}
"strict": true,
将 useUnknownInCatchVariables
设置为 true,然后 "useUnknownInCatchVariables": false,
覆盖它并将其设置回 false。
我的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);
}
你不能在 typescript 中为 catch 子句变量编写特定的注释,这是因为在 javascript 中,catch 子句将捕获抛出的任何异常,而不仅仅是指定类型的异常。
在打字稿中,如果你只想捕获特定类型的异常,你必须捕获抛出的任何异常,检查它是否是你要处理的异常类型,如果不是,则再次抛出。
意思:在做任何事情之前先确保抛出的错误是一个axios错误。
解决方案 1
使用类型断言
使用 AxiosError 投射错误
import { AxiosError } from 'axios';
try {
// do some api fetch
} catch (error) {
const err = error as AxiosError
// console.log(err.response?.data)
if (!err?.response) {
console.log("No Server Response");
} else if (err.response?.status === 400) {
console.log("Missing Username or Password");
} else {
console.log("Login Failed");
}
}
解决方案 2
首先检查错误是否是 axios 错误,然后再做任何事情
import axios from "axios"
try {
// do something
} catch (err) {
// check if the error is an axios error
if (axios.isAxiosError(err)) {
// console.log(err.response?.data)
if (!err?.response) {
console.log("No Server Response");
} else if (err.response?.status === 400) {
console.log("Missing Username or Password");
} else {
console.log("Login Failed");
}
}
}
我有以下代码:
try {
phpDoc(vscode.window.activeTextEditor);
} catch (err) {
console.error(err);
vscode.window.showErrorMessage(err.message);
}
但是 err.message
在 err.
上收到错误 Object is of type 'unknown'.ts(2571)
,但我无法在 catch (err: Error)
中键入对象。
我该怎么办?
因为任何东西都可以抛出,所以unknown
.
const fn = () => {
throw 'foo';
};
try {
fn();
} catch(e) {
console.log(e);
console.log(e instanceof Error);
console.log(e === 'foo');
}
在访问 message
属性.
err
实际上是一个错误以缩小范围
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));
}
}
补充回答CertainPerformance's
在 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 introduced 一个更安全的 catch
子句选项,允许您将参数注释为 unknown
,强制您进行显式类型断言,或者更好, 键入 guard(这使得该子句在编译时和运行时都是安全的)。
但是,为了避免破坏大部分代码库,您必须明确选择加入新行为:
(() => {
try {
throw new Error("ouch!");
} catch(err: unknown) {
console.log(err.message); //Object is of type 'unknown'
}
})();
TypeScript 4.4 引入了一个名为 useUnknownInCatchVariables
的新编译器选项,强制执行此行为。默认情况下它是 false
,但是如果你打开了 strict
选项(正如你应该的那样),它就会打开,这很可能是你首先得到错误的原因。
如果您不想在升级 TypeScript 后更改所有代码但处于严格模式,则可以在 strict
选项后添加以下编译器选项以覆盖它,如
tsconfig.json
{
"compilerOptions": {
[...]
"strict": true,
"useUnknownInCatchVariables": false,
[...]
},
},
}
"strict": true,
将 useUnknownInCatchVariables
设置为 true,然后 "useUnknownInCatchVariables": false,
覆盖它并将其设置回 false。
我的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);
}
你不能在 typescript 中为 catch 子句变量编写特定的注释,这是因为在 javascript 中,catch 子句将捕获抛出的任何异常,而不仅仅是指定类型的异常。
在打字稿中,如果你只想捕获特定类型的异常,你必须捕获抛出的任何异常,检查它是否是你要处理的异常类型,如果不是,则再次抛出。
意思:在做任何事情之前先确保抛出的错误是一个axios错误。
解决方案 1
使用类型断言
使用 AxiosError 投射错误
import { AxiosError } from 'axios';
try {
// do some api fetch
} catch (error) {
const err = error as AxiosError
// console.log(err.response?.data)
if (!err?.response) {
console.log("No Server Response");
} else if (err.response?.status === 400) {
console.log("Missing Username or Password");
} else {
console.log("Login Failed");
}
}
解决方案 2
首先检查错误是否是 axios 错误,然后再做任何事情
import axios from "axios"
try {
// do something
} catch (err) {
// check if the error is an axios error
if (axios.isAxiosError(err)) {
// console.log(err.response?.data)
if (!err?.response) {
console.log("No Server Response");
} else if (err.response?.status === 400) {
console.log("Missing Username or Password");
} else {
console.log("Login Failed");
}
}
}