基于Array.isArray()的显式返回类型

时间:2018-11-06 17:59:32

标签: typescript

我有一个函数可以返回类型OO[]

public convert(data?: I | I[]) {
  if (data) {
    this.input(data);
  }

  if (!this._data) {
    const e = new Error("You must first set the data before trying to convert!");
    e.name = "NotReady";
    throw e;
  }

  return Array.isArray(this._data)
    ? this._convertArray(this._data) as O
    : this._convertObject(this._data) as O[];
}

返回类型取决于用户输入的数据:

public input(data: I | I[]) {
  this._data = data;
  return this;
}

总结:

  • 如果用户发送的输入为Iconvert()将返回类型为O的输出
  • 如果用户发送的输入为I[]convert()将返回类型为O[]的输出

最初,我认为返回convert的条件语句就足够了,但这行不通。我猜我没有足够的创造力,但是我碰壁了。任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:0)

参考您的评论:“转换返回就足够了,但是那行不通。” 您看到棉绒错误还是在运行时出错?

我在下面列出了一些示例代码,这些代码返回正确的内容/类型并执行我认为您需要的操作。我至少做了两个提示类型的添加-也许这就是您的代码所需要的?

interface I {
  id: number;
}

interface O {
  guid: number;
}

class StackOverFlowQuestionClass {
  _data: I | I[];

  public convert(data?: I): O;
  public convert(data?: I[]): O[];

  public convert(data?: I | I[]): O | O[] {
    if (data) {
      this.input(data);
    }

    if (!this._data) {
      const e = new Error(
        "You must first set the data before trying to convert!"
      );
      e.name = "NotReady";
      throw e;
    }

    return Array.isArray(this._data)
      ? (this._convertArray(this._data as I[]) as O[])
      : (this._convertObject(this._data as I) as O);
  }

  public input(data: I | I[]) {
    this._data = data;
    return this;
  }

  public _convertArray(items: I[]): O[] {
    return items.map(item => this._convertObject(item));
  }

  public _convertObject(item: I): O {
    return { guid: item.id };
  }
}

答案 1 :(得分:0)

似乎没有办法避免convert的返回类型含糊不清,因此为了简化客户端调用,我以以下方式扩展了公共API:

public convertArray(data?: I[]) {
  if(!data && !Array.isArray(this._data)) {
    const e = new Error(`Using convertArray() requires that the input is also an array and it is of type ${typeof this._data}`);
    e.name = "TypedMapper::InvalidFormat";
    throw e;
  }
  return this.convert(data) as O[];
}

public convertObject(data?: I) {
  if(!data && Array.isArray(this._data)) {
    const e = new Error(`Using convertObject() requires that the input is an object and it is of type ${typeof this._data}`);
    e.name = "TypedMapper::InvalidFormat";
    throw e;
  }
  return this.convert(data) as O;
}

客户端仍然可以使用convert(),但需要进行类型转换才能有效使用。相反,更方便的语法是:

 const result = tm.convertObject(objInput); // typed to O
 const result2 = tm.convertArray(arrInput); // typed to O[]

答案 2 :(得分:0)

从TypeScript 2.8开始,您可以使用conditional types

class Test<I, O> {
  private _data!: I | I[];

  convert<T extends I | I[]>(data?: T): T extends I[] ? O[] : O {
    if (data) {
      this.input(data);
    }

    if (!this._data) {
      const e = new Error('You must first set the data before trying to convert!');
      e.name = 'NotReady';
      throw e;
    }

    // note the `as any` you can use a // @ts-ignore comment if you prefer
    // @ts-ignore
    return Array.isArray(this._data) ? (this._convertArray(this._data as I[]) as any) : (this._convertObject(this._data as I) as any);
  }

  private input(data: I | I[]): void {
    // ...
  }
  private _convertArray(data: I[]): O[] {
    // ...
  }
  private _convertObject(data: I): O {
    // ...
  }
}

const a: Test<string, number> = new Test();

const b = a.convert(''); // number
const c = a.convert(['']); // number[]