Typescript 2.x控制流程没有拾取类型

时间:2016-12-22 15:16:30

标签: typescript

我有一个函数,其中input是Dictionary或Dictionaries数组:

public convert(input: IDictionary<any> | IDictionary<any>[], additionalProps?: string[]) {
  if ( input instanceof Array ) {
    this._handlers.forEach(fn => {
      input = input.map(i => fn(i));
    });
    return input.map(i => this._convert(i, additionalProps));
  } else {
    this._handlers.forEach(fn => {
      input = fn(input);
    });
    return this._convert(input, additionalProps);
  }
}

该函数执行我需要的功能但是Typescript没有正确识别 if 块中的input引用总是将成为一个数组,因此它给出了以下错误:

  

“IDictionary”

类型中不存在“地图”属性

我会想到使用Typescript 2.x它会使用if块作为其控制流分析的一部分来确定联合类型现在只能是IDictionary<any>[]类型。我的理解错了吗?有没有正确的方法来表明这一点?

P.S。我正在使用Typescript 2.1.4

处理程序的其他一些背景信息:

export default class Mapper {
  private _handlers: Function[] = [];
使用以下公共接口设置

和处理程序:

public handlers(fn: Function | Function[]) {
  if(fn instanceof Array) {
    this._handlers.concat(fn);
  } else {
    this._handlers.push(fn);
  }

  return this;
}

可以在此gist中找到整个班级。 mapper类的一个示例用法是......

const mapping: IMapping = {
  id: 'invoiceId',
  type: (context) => context['type'] === 'ACCREC' ? 'accounts-receivable' : 'accounts-payable',
  date: (context) => xero.xeroDate(context['date']),
  dueDate: (context) => xero.xeroDate(context['dueDate']),
  lastUpdated: (context) => xero.xeroDate(context['updatedDateUtc']),
  payments: (context) => context['payments'].map((p: IDictionary<any>) => p['PaymentID']),
  prePayments: (context) => context['prepayments'].map((p: IDictionary<any>) => p['PaymentID']),
  overPayments: (context) => context['overpayments'].map((p: IDictionary<any>) => p['PaymentID'])
};

const mapper = new Mapper(mapping);
return mapper
  .handler(utils.camelCaseProperties)  
  .convert(invoices);

最后,IDictionary定义为:

interface IDictionary<T> {
  [key: string]: T;
};

2 个答案:

答案 0 :(得分:1)

问题是您要在两个不同的地方更改input的类型:

input = input.map(i => fn(i));

input = fn(input);

你可以这样做:

public convert(input: IDictionary<any> | IDictionary<any>[], additionalProps?: string[]) {
    let input2;

    if ( input instanceof Array ) {
        this._handlers.forEach(fn => {
            input2 = input.map(i => fn(i));
        });

        return input2.map(i => this._convert(i, additionalProps));
    } else {
        this._handlers.forEach(fn => {
            input2 = fn(input);
        });

        return this._convert(input2, additionalProps);
    }
}

或者将_handler的类型更改为:

private _handlers = [] as Array<() => IDictionary<any>[]>;

答案 1 :(得分:0)

使用type assertion

if ( input instanceof Array ) {
    let inputArray = <IDictionary<any>[]> input;
    this._handlers.forEach(fn => {
      inputArray = inputArray.map(i => fn(i));
    });
    // ...
}