英文:
How do I tell TypeScript that my Type has changed/narrowed?
问题
以下是您要翻译的内容:
我有一个用于我的应用程序的 API 代码的类:
```typescript
export class Api {
...
static requestData = async (
abortController: React.MutableRefObject<AbortController | null>
) => {
// 如果有先前的请求,取消它
if (abortController.current) {
abortController.current.abort();
}
// 为新请求设置新的控制器
abortController.current = new AbortController();
try {
const response = await instance.get(
"request/url/string",
{ signal: abortController.current.signal, },
);
if (response.success) {
// 处理成功的响应
} else {
// 处理已知错误
}
} catch (err: unknown) {
const signal = abortController.current.signal;
if (abortController.current.signal.aborted) {
// 处理被取消的请求
} else {
// 处理未知错误
}
}
};
Axios 实例在之前被定义,使用 axios.create
:
const instance = axios.create({
baseURL: "base-url-path",
});
我想要重构代码,用于取消请求和创建新的 AbortController
:
// 如果有先前的请求,取消它
if (abortController.current) {
abortController.current.abort();
}
// 为新请求设置新的控制器
abortController.current = new AbortController();
将其移到自己的函数中(以便在其他地方重用并减少重复的代码)。
尝试 1
我尝试将上面的代码移到类的内部成为一个函数:
public static abortPreviousAndSetUpNewController = (
abortController: React.MutableRefObject<AbortController | null>
) => {
// 如果有先前的请求,取消它
if (abortController.current) {
abortController.current.abort();
}
// 为新请求设置新的控制器
abortController.current = new AbortController();
};
这样我可以这样做:
static requestData = async (
abortController: React.MutableRefObject<AbortController | null>
) => {
this.abortPreviousAndSetUpNewController();
try {
const response = await instance.get(
"request/url/string",
{ signal: abortController.current.signal, },
);
if (response.success) {
// 处理成功的响应
} else {
// 处理已知错误
}
} catch (err: unknown) {
const signal = abortController.current.signal;
if (abortController.current.signal.aborted) {
// 处理被取消的请求
} else {
// 处理未知错误
}
}
};
但我收到错误消息:'abortController.current' is possibly 'null'.ts(18047)
尝试 2
我还尝试使用 is
关键字
让我考虑使用 is
的示例代码:
export const notNullNorUndefined = <T = any>(
value: T
): value is NonNullable<T> => value !== null && value !== undefined;
如果一个可能为 null
/undefined
的对象被传递给这个函数,如果结果是 true
,编译器将接受传递给此函数的对象类型不再是 null | undefined
。
尝试 2 的代码:
public static abortPreviousAndSetUpNewController = (
abortController: React.MutableRefObject<AbortController | null>
): abortController is React.MutableRefObject<AbortController | null> => {
// 如果有先前的请求,取消它
if (abortController.current) {
abortController.current.abort();
}
// 为新请求设置新的控制器
abortController.current = new AbortController();
}
但这会返回语法错误:A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.
如何告诉 TypeScript 我的函数 (abortPreviousAndSetUpNewController
) 已经改变了 abortController.current
,所以它的类型不再是 AbortController | null
,而只是 AbortController
?我尽量避免断言类型。
请注意,我的软件包版本是:
- axios - 0.24.0
- react - 16.14.0
这是您的翻译。如果您需要更多帮助,请告诉我。
<details>
<summary>英文:</summary>
I have a class that houses my API code for my application:
```typescript
export class Api {
...
static requestData = async (
abortController: React.MutableRefObject<AbortController | null>
) => {
// If previous request, cancel
if (abortController.current) {
abortController.current.abort();
}
// Set new controller for new request
abortController.current = new AbortController();
try {
const response = await instance.get(
"request/url/string",
{ signal: abortController.current.signal, },
);
if (response.success) {
// Handle successful response
} else {
// Handle known error
}
} catch (err: unknown) {
const signal = abortController.current.signal;
if (abortController.current.signal.aborted) {
// Handle aborted request
} else {
// Handle unknown error
}
}
};
The Axios instance is defined earlier, using axios.create
const instance = axios.create({
baseURL: "base-url-path",
});
I want to refactor the code that aborts and creates the new AbortController
// If previous request, cancel
if (abortController.current) {
abortController.current.abort();
}
// Set new controller for new request
abortController.current = new AbortController();
into its own function (to be reused elsewhere and reduce the amount of repeated code).
Attempt 1
I tried to move the above code to its own function inside the class:
public static abortPreviousAndSetUpNewController = (
abortController: React.MutableRefObject<AbortController | null>
) => {
// If previous request, cancel
if (abortController.current) {
abortController.current.abort();
}
// Set new controller for new request
abortController.current = new AbortController();
};
So that I could do the following:
static requestData = async (
abortController: React.MutableRefObject<AbortController | null>
) => {
this.abortPreviousAndSetUpNewController();
try {
const response = await instance.get(
"request/url/string",
{ signal: abortController.current.signal, },
);
if (response.success) {
// Handle successful response
} else {
// Handle known error
}
} catch (err: unknown) {
const signal = abortController.current.signal;
if (abortController.current.signal.aborted) {
// Handle aborted request
} else {
// Handle unknown error
}
}
};
But I get the error: 'abortController.current' is possibly 'null'.ts(18047)
Attempt 2
I also tried to use the is
keyword
Example code that made me consider using is
:
export const notNullNorUndefined = <T = any>(
value: T
): value is NonNullable<T> => value !== null && value !== undefined;
If a potentially null
/undefined
object is passed to this function, if the result is true
the compiler accepts that the type of the object passed cannot be null | undefined
anymore.
Attempt 2 code:
public static abortPreviousAndSetUpNewController = (
abortController: React.MutableRefObject<AbortController | null>
): abortController is React.MutableRefObject<AbortController | null> => {
// If previous request, cancel
if (abortController.current) {
abortController.current.abort();
}
// Set new controller for new request
abortController.current = new AbortController();
}
But this returns syntax errors: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.
How do I tell TypeScript that my function (abortPreviousAndSetUpNewController
) has mutated abortController.current
so that its' type is no longer AbortController | null
and only AbortController
?
I would prefer not to assert the type where possible
Note, my package versions are:
- axios - 0.24.0
- react - 16.14.0
答案1
得分: 0
After Jerryh001的提示以及另一个答案的帮助(在下面链接中),我能够找到解决方案:
public static abortPreviousAndSetUpNewController(
abortController: React.MutableRefObject<AbortController | null>
): asserts abortController is React.MutableRefObject<AbortController> {
// 如果之前有请求,取消
if (abortController.current) {
abortController.current.abort();
}
// 为新请求设置新控制器
abortController.current = new AbortController();
}
这意味着我可以得到所需的代码:
static requestData = async (
abortController: React.MutableRefObject<AbortController | null>
) => {
this.abortPreviousAndSetUpNewController();
try {
const response = await instance.get(
"request/url/string",
{ signal: abortController.current.signal, },
);
if (response.success) {
// 处理成功的响应
} else {
// 处理已知错误
}
} catch (err: unknown) {
const signal = abortController.current.signal;
if (abortController.current.signal.aborted) {
// 处理已中止的请求
} else {
// 处理未知错误
}
}
};
注意:
根据此答案:
请记住,TypeScript 不能在断言中使用箭头函数。
该答案提供了一个链接,指向此问题,该问题进一步提到了一个建议。
不幸的是,这两个线程都被标记为“已关闭”,所以目前不能在使用asserts
关键字时使用箭头函数。
英文:
After Jerryh001's hint and help from another answer (linked below), I was able to get to a solution:
public static abortPreviousAndSetUpNewController(
abortController: React.MutableRefObject<AbortController | null>
): asserts abortController is React.MutableRefObject<AbortController> {
// If previous request, cancel
if (abortController.current) {
abortController.current.abort();
}
// Set new controller for new request
abortController.current = new AbortController();
}
Which meant that I could have the desired code:
static requestData = async (
abortController: React.MutableRefObject<AbortController | null>
) => {
this.abortPreviousAndSetUpNewController();
try {
const response = await instance.get(
"request/url/string",
{ signal: abortController.current.signal, },
);
if (response.success) {
// Handle successful response
} else {
// Handle known error
}
} catch (err: unknown) {
const signal = abortController.current.signal;
if (abortController.current.signal.aborted) {
// Handle aborted request
} else {
// Handle unknown error
}
}
};
Note:
As per this answer:
> keep in mind that TypeScript cannot use arrowFunctions for assertions.
The answer posts a link to this issue which follows on to a suggestion.
Unfortunately, both of these threads are marked as "closed" so for the time-being you can't use arrow functions when using the asserts
keyword.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论