fai*_*wer 7 javascript typescript
在使用 TypeScript 的过程中,我对一种常见的 JavaScript 模式有点挣扎。是关于:
这是代码示例:
const wait = (cb: Function) => // just example of a possible callback
new Promise((resolve) =>
setTimeout(() => {
cb();
resolve();
}, 1)
);
async function v1() {
let a: { bool: boolean };
await wait(() => {
a = { bool: true }; // from sinse `a` isn't empty
});
alert(a); // error: Variable 'a' is used before being assigned. ts(2454)
if (a === undefined) return; // error: Variable 'a' is used ...
alert(a); // only now it's okay: { bool: true }
}
Run Code Online (Sandbox Code Playgroud)
如你看到的:
a可能未初始化好的。如果我只添加一些检查和可能性,我会怎样null:
async function v2() {
let a: { bool: boolean } | null = null;
await wait(() => {
a = { bool: true };
});
alert(a); // no error
alert(a.bool); // error: possibly null
if (a === undefined || a === null) return;
alert(a.bool); // error: Property 'bool' does not exist on type 'never' ts(2339)
}
Run Code Online (Sandbox Code Playgroud)
所以现在 TypeScript 知道它不是零。所以……一定是这样{ bool: boolean }。但是... TypeScript 认为它是无法访问的代码分支,因此类型是never.
是否有任何简单合理的解决方案可以说服 TypeScript 代码是正确的并且类型是正确的{ bool: boolean }?
例如:
// @tsignore, as MyType, !, 忽略 linter 规则这些 ^ 对我来说看起来不太好:) 我想我错过了一些重要的事情。
我的 tsconfig:
{
"compilerOptions": {
"sourceMap": true,
"module": "commonjs",
"moduleResolution": "node",
"esModuleInterop": true,
"target": "ES2019",
"allowJs": false,
"checkJs": false,
"strict": true,
"resolveJsonModule": true,
"lib": ["ES2019", "DOM"],
"types": ["jest", "node"],
"typeRoots": ["./src/types", "./node_modules/@types"],
"outDir": "./build",
"baseUrl": "./src/",
"paths": { "~/*": ["*"] }
},
...
}
Run Code Online (Sandbox Code Playgroud)
这是多种因素共同作用的结果。
主要问题是编译器不会通过深入函数调用内部、查找该函数的实现并检查任何封闭变量的状态是否已更改来执行控制流分析。这将是“正确”的行为,但对于编译器来说,为了跟踪此类状态更改而实质上模拟每个程序的运行,在时间和内存方面将非常昂贵。问题“当调用函数时,编译器应该假设其副作用是什么?” 这是一个很难回答的问题,GitHub 上有一个关于此问题的讨论:microsoft/TypeScript#9998。
当前的编译器本质上假设函数调用没有副作用。因此,如果在调用a之前未设置wait(),则编译器之后也会将其视为未设置。对于您的情况而言,情况并非如此,但在很多很多情况下,这是所需的行为。这是一个权衡。因此,我们需要想出一些解决方法,使编译器在调用a后将其视为“可能设置” wait(),而不依赖编译器为我们执行此操作。
您初始化a为类似nullor 的第二种方法undefined是有希望的,但不幸的是您遇到了另一个问题:如果您为联合类型变量分配一个值,控制流分析将缩小变量的类型。因此let a: { bool: boolean } | null = null;,在 之后,编译器将视为a类型,null直到并且除非它被重新分配。有关更多信息,请参阅microsoft/TypeScript#8513 。这又常常是一件好事。毕竟,如果我们不尝试解决其他问题,您会希望编译器认为a存在null该问题。
这里的解决方法(在上一期中间接提到)可能是使用类型断言来告诉编译器null不要将其视为类型null,而是将其视为联合类型{ bool: boolean } | null:
let a = null as { bool: boolean } | null;
Run Code Online (Sandbox Code Playgroud)
现在您可以调用wait(),之后 的推断类型a没有改变(由于#9998)并且仍然是并集。然后下面的其他代码将按预期运行:
if (a === undefined || a === null) return;
alert(a.bool); // okay
Run Code Online (Sandbox Code Playgroud)
那么,是吗?无论如何,它并不完美,但考虑到当前的 TypeScript 化身,它是我能建议的最好的了。无论如何,希望有帮助;祝你好运!
| 归档时间: |
|
| 查看次数: |
1153 次 |
| 最近记录: |