为什么这种字符串类型保护不起作用?
Why isn't this type guard for string working?
我有一个接受参数的 TypeScript 方法。参数可以是 string
类型或 Object
类型。当我在方法主体中使用 typeof
检查类型 string
时,我仍然收到错误消息,指出 indexOf
和 substr
未在类型 string | Object
上找到。
据我了解,if
块体应该由条件进行类型保护。我做错了什么?
function mergeUrlParameters(sourceParameters: string | Object, targetUrl: string, overwrite: boolean = false): string {
var sourceParamObject: Object;
if (typeof sourceParameters === "string") {
if (sourceParameters.indexOf("?") >= 0)
sourceParameters = sourceParameters.substr(sourceParameters.indexOf("?") + 1);
sourceParamObject = $.deparam(sourceParameters, true);
} else {
sourceParamObject = sourceParameters;
}
...
}
我正在使用 Visual Studio 2015 并安装了最新的 TypeScript (1.8.x)。
更新
事实证明,sourceParameters
变量的重新分配导致类型保护失败。我已经发布了关于此行为的相关潜在错误报告 here。同时,有几个简单的解决方法可用,我选择使用 ?
条件表达式内联检查和子字符串调用。
您需要将其转换为合适的类型:
function mergeUrlParameters(sourceParameters: string | Object, targetUrl: string, overwrite: boolean = false): string {
var sourceParamObject: Object;
if (typeof sourceParameters === "string") {
if ((<string> sourceParameters).indexOf("?") >= 0) {
sourceParameters = (<string> sourceParameters).substr((<string> sourceParameters).indexOf("?") + 1);
}
sourceParamObject = $.deparam((<string> sourceParameters), true);
} else {
sourceParamObject = sourceParameters;
}
...
}
编辑
如果你想避免这种转换,你可以创建你自己的类型保护(你的代码中没有):
function isString(x: any): x is string {
return typeof x === "string";
}
然后:
function mergeUrlParameters(sourceParameters: string | Object, targetUrl: string, overwrite: boolean = false): string {
var sourceParamObject: Object;
if (isString(sourceParameters)) {
if (sourceParameters.indexOf("?") >= 0) {
sourceParameters = sourceParameters.substr(sourceParameters.indexOf("?") + 1);
}
sourceParamObject = $.deparam(sourceParameters, true);
} else {
sourceParamObject = sourceParameters;
}
...
}
更多信息在TypeScript Handbook | typeof type guards
第二次编辑
好的,玩了一会儿我明白你的代码是什么编译器问题了。
您的代码的这种变体编译没有错误:
function mergeUrlParameters(sourceParameters: string | Object, targetUrl: string, overwrite: boolean = false): string {
var sourceParamObject: Object;
if (typeof sourceParameters === "string") {
sourceParamObject = $.deparam(sourceParameters.indexOf("?") >= 0 ?
sourceParameters.substr(sourceParameters.indexOf("?") + 1)
: sourceParameters
, true);
} else {
sourceParamObject = sourceParameters;
}
}
主要区别在于您在代码中将值重新分配给 sourceParameters
,这可能会使编译器感到困惑。
为了说明这个问题,考虑这个简单的例子:
function x(param: number | string): number {
var num: number;
if (typeof param === "string") {
num = parseInt(param);
} else {
num = param;
}
return num;
}
function y(param: number | string): number {
if (typeof param === "string") {
param = parseInt(param);
}
return param;
}
函数x
编译没有错误,但是y
有如下错误:
Argument of type 'number | string' is not assignable to parameter of type 'string'. Type 'number' is not assignable to type 'string'
(在 the playground 中查看)
我有一个接受参数的 TypeScript 方法。参数可以是 string
类型或 Object
类型。当我在方法主体中使用 typeof
检查类型 string
时,我仍然收到错误消息,指出 indexOf
和 substr
未在类型 string | Object
上找到。
据我了解,if
块体应该由条件进行类型保护。我做错了什么?
function mergeUrlParameters(sourceParameters: string | Object, targetUrl: string, overwrite: boolean = false): string {
var sourceParamObject: Object;
if (typeof sourceParameters === "string") {
if (sourceParameters.indexOf("?") >= 0)
sourceParameters = sourceParameters.substr(sourceParameters.indexOf("?") + 1);
sourceParamObject = $.deparam(sourceParameters, true);
} else {
sourceParamObject = sourceParameters;
}
...
}
我正在使用 Visual Studio 2015 并安装了最新的 TypeScript (1.8.x)。
更新
事实证明,sourceParameters
变量的重新分配导致类型保护失败。我已经发布了关于此行为的相关潜在错误报告 here。同时,有几个简单的解决方法可用,我选择使用 ?
条件表达式内联检查和子字符串调用。
您需要将其转换为合适的类型:
function mergeUrlParameters(sourceParameters: string | Object, targetUrl: string, overwrite: boolean = false): string {
var sourceParamObject: Object;
if (typeof sourceParameters === "string") {
if ((<string> sourceParameters).indexOf("?") >= 0) {
sourceParameters = (<string> sourceParameters).substr((<string> sourceParameters).indexOf("?") + 1);
}
sourceParamObject = $.deparam((<string> sourceParameters), true);
} else {
sourceParamObject = sourceParameters;
}
...
}
编辑
如果你想避免这种转换,你可以创建你自己的类型保护(你的代码中没有):
function isString(x: any): x is string {
return typeof x === "string";
}
然后:
function mergeUrlParameters(sourceParameters: string | Object, targetUrl: string, overwrite: boolean = false): string {
var sourceParamObject: Object;
if (isString(sourceParameters)) {
if (sourceParameters.indexOf("?") >= 0) {
sourceParameters = sourceParameters.substr(sourceParameters.indexOf("?") + 1);
}
sourceParamObject = $.deparam(sourceParameters, true);
} else {
sourceParamObject = sourceParameters;
}
...
}
更多信息在TypeScript Handbook | typeof type guards
第二次编辑
好的,玩了一会儿我明白你的代码是什么编译器问题了。
您的代码的这种变体编译没有错误:
function mergeUrlParameters(sourceParameters: string | Object, targetUrl: string, overwrite: boolean = false): string {
var sourceParamObject: Object;
if (typeof sourceParameters === "string") {
sourceParamObject = $.deparam(sourceParameters.indexOf("?") >= 0 ?
sourceParameters.substr(sourceParameters.indexOf("?") + 1)
: sourceParameters
, true);
} else {
sourceParamObject = sourceParameters;
}
}
主要区别在于您在代码中将值重新分配给 sourceParameters
,这可能会使编译器感到困惑。
为了说明这个问题,考虑这个简单的例子:
function x(param: number | string): number {
var num: number;
if (typeof param === "string") {
num = parseInt(param);
} else {
num = param;
}
return num;
}
function y(param: number | string): number {
if (typeof param === "string") {
param = parseInt(param);
}
return param;
}
函数x
编译没有错误,但是y
有如下错误:
Argument of type 'number | string' is not assignable to parameter of type 'string'. Type 'number' is not assignable to type 'string'
(在 the playground 中查看)