打字稿即使声明也找不到属性

时间:2020-06-09 14:13:06

标签: typescript

由于类型已过时,因此我正在尝试为正在使用的包修改类型声明。我可以很好地调整大多数内容,但是似乎无法解决一个错误,那就是该函数返回的接口的属性。

这是一个代码示例。我已经剥离了代码,我敢肯定与该问题无关,以便于阅读。如果您觉得缺少某些可能有助于理解该问题的信息,请告诉我。

declare namespace renderContent {
  type renderContentCallback = (
    eventOrImage: Event | HTMLCanvasElement | HTMLImageElement,
    data?: MetaData
  ) => void;

  interface ImageHead {
    imageHead?: ArrayBuffer | Uint8Array;
  }

  interface MetaData extends ImageHead {
    //...
  }

  interface PromiseData extends MetaData {
    image: HTMLCanvasElement | HTMLImageElement;
  }

  interface BasicOptions {
    //...
  }

  type renderContentOptions = BasicOptions
}

interface renderContent {
  (
    file: File | Blob | string,
    /* If options are defined instead of a callback function, the next argument will be skipped and the function will return a promise */
    callbackOrOption?: renderContent.renderContentCallback | renderContent.renderContentOptions,
    options?: renderContent.renderContentOptions
  ): HTMLImageElement | FileReader | Promise<renderContent.PromiseData> | false;
}

declare const renderContent: renderContent;

export = renderContent;

然后当我在代码中像这样使用它时:

const { image } = await renderContent(file, options);

我收到一条错误消息:

类型“ false”上不存在属性“图像” | HTMLImageElement | FileReader | PromiseData'

在我看来,错误消息中列出的 PromiseData 接口中似乎已明确定义了它。那我想念什么?

1 个答案:

答案 0 :(得分:3)

问题是,打字稿无法确定renderContent返回的类型将是Promise<renderContent.PromiseData>。实际上,对于打字稿,类型也可以是FileReaderHtMLImageElement ...

这些类型没有键image,这就是为什么出现此错误的原因。

我想您认为使用关键字await会使打字稿猜测Promise<renderContent.PromiseData>是正确的返回类型,但不幸的是不是。


为了告诉打字稿您在等待什么,请使用关键字as,例如:

playground

const { image } = await (renderContent(_) as Promise<renderContent.PromiseData>);

关于解决方案:

它可能有效,但有副作用。例如:

如果您使用类似的功能:

 const data = renderContent(false as unknown as File);

使用打字稿,您最多可以调用data.readAsArrayBufferdata.height,这是错误的。因为renderContent返回一个HTMLCanvasElement,所以返回一个HTMLImageElement


一个新的解决方案!进行一些返工:

考虑到所有问题,更好的解决方案是准确描述renderContent调用方案的外观:

type possibilityA = (
    file: File | Blob | string,
    options: renderContent.renderContentOptions
) => Promise<renderContent.PromiseData>;

type possibilityB = (
    file: File | Blob | string,
    callback: renderContent.renderContentCallback,
) => HTMLImageElement | FileReader | false;

type possibilityC = (
    file: File | Blob | string,
    callback: renderContent.renderContentCallback,
    options: renderContent.renderContentOptions
) => HTMLImageElement | FileReader | false;

type renderContent = possibilityA & possibilityB & possibilityC;

declare const renderContent: renderContent;

(async() => {
  const data = await renderContent('foo', {  });
})();

playground

在这种情况下,打字稿将根据您提供的参数来选择适当的重载,该参数将相应地定义data的类型。