TS7017暗含任何类型+类型推断

时间:2018-07-30 23:56:08

标签: typescript type-inference

这是错误的压缩摘要:

export default function formatSql(this: EscapeFunctions, sqlQuery: string, values: QueryParams) {

    if (isPlainObject(values)) {
        console.log(values[p]); // <-- Element implicitly has an 'any' type because type 'QueryParams' has no index signature.
    } else if (Array.isArray(values)) {
        // ...
    } else {
        throw new Error(`Unsupported values type`);
    }
    // ...
}

QueryParams定义为:

export type QueryParams = StringMap | any[];
export interface StringMap {
    [_:string]: any,
}

因此,如果我没有记错的话,StringMap具有“索引签名”,并且isPlainObject定义为:

export function isPlainObject(obj: any): obj is object  {
    return isObject(obj) && (
        obj.constructor === Object  // obj = {}
        || obj.constructor === undefined // obj = Object.create(null)
    );
}

因此,我认为isPlainObject检查将排除any[]类型,因此,values应该被推断为StringMap,但这不是似乎是正在发生的事情。

即使我让isPlainObject返回obj is StringMap,Typescript仍然会抱怨。

为什么?我有什么办法可以在不进行所有类型转换的情况下完成这项工作?

1 个答案:

答案 0 :(得分:2)

从技术上讲,数组仍然符合类型{[key: string]: any}。您可以通过执行const test: StringMap = [];进行验证。 TypeScript编译器不会抱怨。因此,您首先必须排除values是数组的可能性。

接下来,函数isPlainObject的返回类型定义为obj is object。这太通用了,会使您的代码块“忘记”该对象具有索引签名。它必须为obj is StringMap

因此,在实践中,您需要做两件事:

  1. 在您的第一个if语句中,检查该值是否为数组
  2. 将您的isPlainObject返回类型声明更改为obj is StringMap

基本上,它看起来像这样:

export function isPlainObject(obj: any): obj is StringMap  {
  // ...
}

export default function formatSql(values: QueryParams) {
  if (Array.isArray(values)) {
    // ...
  } else if (isPlainObject(values)) {
    console.log(values[p]);
  } else {
    throw new Error(`Unsupported values type`);
  }
}