为什么这种类型的防护不能用于字符串工作?

时间:2016-04-12 09:22:26

标签: typescript typescript1.8

我有一个接受参数的TypeScript方法。参数可以是string类型,也可以是Object类型。当我在方法正文中对typeof类型进行string检查时,仍然会收到错误消息,指出在indexOf类型上找不到substrstring | 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;
  }

  ...
}

我正在使用安装了最新TypeScript的Visual Studio 2015(1.8.x)。

更新

事实证明,sourceParameters变量的重新分配会导致类型保护失败。我发布了一个有关此行为的相关潜在错误报告here。与此同时,我可以使用几种简单的解决方法,我选择使用?条件表达式内联检查和子串调用。

1 个答案:

答案 0 :(得分:0)

您需要将其转换为适当的类型:

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中查看)