在使用 TypeScript 期间,我对一种常见的 JavaScript 模式有点挣扎。是关于:
- 声明一些“let”变量而不为其设置任何初始值
- 在某个回调中将此值设置为变量
- 执行回调后使用此变量
这是代码示例:
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 }
}
如你看到的:
- TypeScript 理解这一点
a
可能未初始化
- 但同时 TS 不明白它可能被初始化
好的。如果我只添加一些检查和可能性会怎样?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)
}
所以现在 TypeScript 知道它不是零。所以……一定是{ bool: boolean }
。但是... TypeScript 认为它是无法访问的代码分支,所以类型是never
.
是否有任何简单合理的解决方案可以说服 TypeScript 代码是正确的并且类型是正确的{ bool: boolean }
?
E.g.:
- 我可以设置非空初始值。但实际上通常这是不可能的(因为有更复杂的类型)
- 我可以用
// @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": { "~/*": ["*"] }
},
...
}