Tom*_*Tom 12 javascript node.js typescript
我有以下功能:
/**
* Retrieves a component template from filesystem
*/
const getComponentTemplate = async (
p: string
): Promise<string> => {
let template: string
try {
template = await fs.readFile(p, {
encoding: 'utf8'
})
} catch (e) {
if (e instanceof Error && e.code === 'ENOENT') {
throw new Error(`template for element type ${elementType} not found`)
}
throw e
}
return template
}
Run Code Online (Sandbox Code Playgroud)
打字稿在这里抱怨:
[ts] Property 'code' does not exist on type 'Error'
这是因为 JavascriptError类只有属性message 和 name。
然而,Node 的Error类确实有一个code 属性。
Typescript 在一个特殊的接口中定义了它ErrnoException(请参阅此处的源代码)。我已经添加@types/node到我的 package.json 中,但这并没有让 Typescript 意识到这Error是接口的一部分ErrnoException。
无法在 catch 子句中声明类型注释。那么,如何让 Typescript 编译器能够解析这是一个节点错误呢?
仅供参考,这是我的一部分tsconfig.json:
{
"compilerOptions": {
"target": "es2017",
"module": "commonjs",
"lib": ["es2017"]
...
}
}
Run Code Online (Sandbox Code Playgroud)
它不是通用的解决方案,但适用于这种ErrnoException情况。根据"@types/node": "16.11.xx"定义,ErrnoException接口是:
interface ErrnoException extends Error {
errno?: number | undefined;
code?: string | undefined;
path?: string | undefined;
syscall?: string | undefined;
}
Run Code Online (Sandbox Code Playgroud)
下面的类型防护完全尊重这种辩护。我的 TypeScript 和 ESLint 设置非常严格,因此您很可能不需要禁用 ESLint/TSLint 的注释(如果您仍然使用这个已弃用的注释)。
interface ErrnoException extends Error {
errno?: number | undefined;
code?: string | undefined;
path?: string | undefined;
syscall?: string | undefined;
}
Run Code Online (Sandbox Code Playgroud)
在哪里
function isErrnoException(error: unknown): error is ErrnoException {
return isArbitraryObject(error) &&
error instanceof Error &&
(typeof error.errno === "number" || typeof error.errno === "undefined") &&
(typeof error.code === "string" || typeof error.code === "undefined") &&
(typeof error.path === "string" || typeof error.path === "undefined") &&
(typeof error.syscall === "string" || typeof error.syscall === "undefined");
}
Run Code Online (Sandbox Code Playgroud)
现在我们可以检查code属性:
import FileSystem from "fs";
import PromisfiedFileSystem from "fs/promises";
// ...
let targetFileStatistics: FileSystem.Stats;
try {
targetFileStatistics = await PromisfiedFileSystem.stat(validAbsolutePathToPublicFile);
} catch (error: unknown) {
if (isErrnoException(error) && error.code === "ENOENT") {
response.
writeHead(HTTP_StatusCodes.notFound, "File not found.").
end();
return;
}
response.
writeHead(HTTP_StatusCodes.internalServerError, "Error occurred.").
end();
}
Run Code Online (Sandbox Code Playgroud)
我在我的库@yamato-daiwa/es-extensions-nodejs中添加了isErrnoException类型保护,但因为我知道第三方解决方案的推广可能很烦人,所以我已经发布了上面使用示例的完整实现 =)
我最终使用了@AndyJ 的评论:
/**
* Retrieves a component template from filesystem
*/
const getComponentTemplate = async (
p: string
): Promise<string> => {
let template: string
try {
template = await fs.readFile(p, {
encoding: 'utf8'
})
} catch (e) {
// tslint:disable-next-line:no-unsafe-any
if (isNodeError(e) && e.code === 'ENOENT') {
throw new Error(`template for element type ${elementType} not found`)
}
throw e
}
return template
}
/**
* @param error the error object.
* @returns if given error object is a NodeJS error.
*/
const isNodeError = (error: Error): error is NodeJS.ErrnoException =>
error instanceof Error
Run Code Online (Sandbox Code Playgroud)
但我惊讶地发现这是必要的。它还要求您禁用 tslint 的unsafe-any 规则(如果您正在使用该规则)。
您可以考虑code使用方括号读取属性,然后检查其值是否等于ENOENT:
try {
...
} catch (e) {
const code: string = e['code'];
if (code === 'ENOENT') {
...
}
throw e
}
Run Code Online (Sandbox Code Playgroud)
这不是一个完美的解决方案,但考虑到您无法在 catch 子句中声明类型并且检查e instanceof ErrnoException无法正常工作(如问题评论中所述),它可能已经足够好了。
| 归档时间: |
|
| 查看次数: |
7628 次 |
| 最近记录: |