TypeScript 运行时类型检查不起作用?
TypeScript runtime type-checks not working?
所以我遇到了一些奇怪的情况:我正在尝试使用 TypeScript 验证 React Web 应用程序的登录请求,并试图将类型检查逻辑分配给布尔值。但是,这样做后,我收到以下错误:
Argument of type 'FamilyInfo | undefined' is not assignable to parameter of type 'FamilyInfo'.
Type 'undefined' is not assignable to type 'FamilyInfo'.
这里是有问题的代码:
makeAPIRequest(loginRequest, (successful: boolean, serverResult: APIResult | undefined) => {
const loginSuccess = (successful && (serverResult !== undefined) && (serverResult.familyInfo !== undefined));
setBadLogin(!loginSuccess);
if (loginSuccess) {
// The line below fails
props.onSuccess(loginRequest, serverResult.familyInfo);
}
});
相关类型如下所示:
interface APIResult {
success: boolean;
familyInfo: FamilyInfo | undefined;
}
interface LoginPanelProps {
onSuccess: (loginInfo: LoginRequest, familyInfo: FamilyInfo) => void;
}
如果我执行以下操作,那么一切正常:
if ((successful && (serverResult !== undefined) && (serverResult.familyInfo !== undefined))) {
props.onSuccess(loginRequest, serverResult.familyInfo);
}
但这当然有点多余,所以我想让它更简洁,并理解为什么类型验证在这里失败。
的 TypeScript 版本 v4.6.2 中看到此失败
我认为这是一个在 Typescript >= 4.4 中修复的问题(或者缺少功能,如果你愿意的话)。
// In TS 4.3 and below
function foo(arg: unknown) {
const argIsString = typeof arg === "string";
if (argIsString) {
console.log(arg.toUpperCase());
// ~~~~~~~~~~~
// Error! Property 'toUpperCase' does not exist on type 'unknown'.
}
}
In TypeScript 4.4, that is no longer the case. The above example works with no errors! When TypeScript sees that we are testing a constant value, it will do a little bit of extra work to see if it contains a type guard. If that type guard operates on a const, a readonly property, or an un-modified parameter, then TypeScript is able to narrow that value appropriately.
看起来这是使用 TypeScript 设计的:https://github.com/microsoft/TypeScript/issues/48241
解决方案看起来像这样:
makeAPIRequest(loginRequest, (successful: boolean, serverResult: APIResult | undefined) => {
// Need to create a const of the familyInfo to be able to nicely check it.
const familyInfo = serverResult?.familyInfo;
const loginSuccess = (successful && (serverResult !== undefined) && serverResult.success && (familyInfo !== undefined));
setBadLogin(!loginSuccess);
if (loginSuccess) {
props.onSuccess(loginRequest, familyInfo);
}
});
所以我遇到了一些奇怪的情况:我正在尝试使用 TypeScript 验证 React Web 应用程序的登录请求,并试图将类型检查逻辑分配给布尔值。但是,这样做后,我收到以下错误:
Argument of type 'FamilyInfo | undefined' is not assignable to parameter of type 'FamilyInfo'.
Type 'undefined' is not assignable to type 'FamilyInfo'.
这里是有问题的代码:
makeAPIRequest(loginRequest, (successful: boolean, serverResult: APIResult | undefined) => {
const loginSuccess = (successful && (serverResult !== undefined) && (serverResult.familyInfo !== undefined));
setBadLogin(!loginSuccess);
if (loginSuccess) {
// The line below fails
props.onSuccess(loginRequest, serverResult.familyInfo);
}
});
相关类型如下所示:
interface APIResult {
success: boolean;
familyInfo: FamilyInfo | undefined;
}
interface LoginPanelProps {
onSuccess: (loginInfo: LoginRequest, familyInfo: FamilyInfo) => void;
}
如果我执行以下操作,那么一切正常:
if ((successful && (serverResult !== undefined) && (serverResult.familyInfo !== undefined))) {
props.onSuccess(loginRequest, serverResult.familyInfo);
}
但这当然有点多余,所以我想让它更简洁,并理解为什么类型验证在这里失败。
的 TypeScript 版本 v4.6.2 中看到此失败我认为这是一个在 Typescript >= 4.4 中修复的问题(或者缺少功能,如果你愿意的话)。
// In TS 4.3 and below
function foo(arg: unknown) {
const argIsString = typeof arg === "string";
if (argIsString) {
console.log(arg.toUpperCase());
// ~~~~~~~~~~~
// Error! Property 'toUpperCase' does not exist on type 'unknown'.
}
}
In TypeScript 4.4, that is no longer the case. The above example works with no errors! When TypeScript sees that we are testing a constant value, it will do a little bit of extra work to see if it contains a type guard. If that type guard operates on a const, a readonly property, or an un-modified parameter, then TypeScript is able to narrow that value appropriately.
看起来这是使用 TypeScript 设计的:https://github.com/microsoft/TypeScript/issues/48241
解决方案看起来像这样:
makeAPIRequest(loginRequest, (successful: boolean, serverResult: APIResult | undefined) => {
// Need to create a const of the familyInfo to be able to nicely check it.
const familyInfo = serverResult?.familyInfo;
const loginSuccess = (successful && (serverResult !== undefined) && serverResult.success && (familyInfo !== undefined));
setBadLogin(!loginSuccess);
if (loginSuccess) {
props.onSuccess(loginRequest, familyInfo);
}
});