112

我只是在 VisualStudio 2012 中测试打字稿,但它的类型系统有问题。我的 html 网站有一个 ID 为“mycanvas”的画布标签。我正在尝试在此画布上绘制一个矩形。这是代码

var canvas = document.getElementById("mycanvas");
var ctx: CanvasRenderingContext2D = canvas.getContext("2d");
ctx.fillStyle = "#00FF00";
ctx.fillRect(0, 0, 100, 100);

不幸的是,VisualStudio 抱怨说

“HTMLElement”类型的值上不存在属性“getContext”

它将第二行标记为错误。我认为这只是一个警告,但代码无法编译。VisualStudio 说

有构建错误。您想继续并运行最后一次成功的构建吗?

我根本不喜欢这个错误。为什么没有动态方法调用?毕竟 getContext 方法肯定存在于我的画布元素上。但是我认为这个问题很容易解决。我刚刚为画布添加了类型注释:

var canvas : HTMLCanvasElement = document.getElementById("mycanvas");
var ctx: CanvasRenderingContext2D = canvas.getContext("2d");
ctx.fillStyle = "#00FF00";
ctx.fillRect(0, 0, 100, 100);

但是类型系统仍然不满意。这是新的错误消息,这次是在第一行:

无法将“HTMLElement”转换为“HTMLCanvasElement”:“HTMLElement”类型缺少“HTMLCanvasElement”类型中的“toDataURL”属性

好吧,我完全支持静态类型,但这使得语言无法使用。类型系统要我做什么?

更新:

Typescript 确实不支持动态调用,我的问题可以通过类型转换来解决。我的问题基本上是这个TypeScript 的副本:casting HTMLElement

4

7 回答 7

246
var canvas = <HTMLCanvasElement> document.getElementById("mycanvas");
var ctx = canvas.getContext("2d");

或使用类型的动态查找any(无类型检查):

var canvas : any = document.getElementById("mycanvas");
var ctx = canvas.getContext("2d");

您可以查看lib.d.ts中的不同类型。

于 2012-12-02T16:23:13.023 回答
15
const canvas =  document.getElementById('stage') as HTMLCanvasElement;
于 2019-02-12T23:55:07.293 回答
12

虽然其他答案提倡类型断言(这就是它们的本质——TypeScript 没有真正改变类型的类型转换;它们只是抑制类型检查错误的一种方式),解决问题的理智诚实的方法是倾听错误信息。

在你的情况下,有 3 件事可能出错:

  • document.getElementById("mycanvas")可能会返回null,因为找不到该 id 的节点(它可能已被重命名,尚未注入到文档中,有人可能尝试在无法访问 DOM 的环境中运行您的函数)
  • document.getElementById("mycanvas")可能会返回对 DOM 元素的引用,但该 DOM 元素不是HTMLCanvasElement
  • document.getElementById("mycanvas")确实返回了一个有效的HTMLElement,它确实是一个HTMLCanvasElement,但CanvasRenderingContext2D浏览器不支持。

我建议不要让编译器关闭(并且可能会发现自己处于Cannot read property 'getContext' of null抛出无用错误消息的情况),而是建议控制您的应用程序边界。

确保元素包含 HTMLCanvasElement

const getCanvasElementById = (id: string): HTMLCanvasElement => {
    const canvas = document.getElementById(id);

    if (!(canvas instanceof HTMLCanvasElement)) {
        throw new Error(`The element of id "${id}" is not a HTMLCanvasElement. Make sure a <canvas id="${id}""> element is present in the document.`);
    }

    return canvas;
}

确保浏览器支持渲染上下文

const getCanvasRenderingContext2D = (canvas: HTMLCanvasElement): CanvasRenderingContext2D => {
    const context = canvas.getContext('2d');

    if (context === null) {
        throw new Error('This browser does not support 2-dimensional canvas rendering contexts.');
    }

    return context;
}

用法:

const ctx: CanvasRenderingContext2D = getCanvasRenderingContext2D(getCanvasElementById('mycanvas'))

ctx.fillStyle = "#00FF00";
ctx.fillRect(0, 0, 100, 100);

请参阅TypeScript 游乐场

于 2019-02-13T03:23:57.833 回答
2

这似乎在 .9 版本的 TypeScript 中得到纠正:http: //blogs.msdn.com/b/typescript/archive/2013/03/25/working-on-typescript-0-9-generics-overload- on-constants-and-compiler-performance.aspx 请参阅“常量重载”部分,其中明确显示了画布标记。

于 2013-05-08T16:43:32.093 回答
1

我遇到了同样的问题,但使用的是 SVGSVGElement 而不是 HTMLCanvasElement。转换为 SVGSVGElement 会导致编译时错误:

var mySvg = <SVGSVGElement>document.getElementById('mySvg');

无法将“HTMLElement”转换为“SVGSVGElement”:
“HTMLElement”类型缺少“SVGSVGElement”类型的属性“width”。
“SVGSVGElement”类型缺少“HTMLElement”类型的“onmouseleave”属性。

如果通过首先转换为“任何”来修复它:

var mySvg = <SVGSVGElement><any>document.getElementById('mySvg');

或者这样(它具有相同的效果)

var mySvg: SVGSVGElement = <any>document.getElementById('mySvg');

现在 mySvg 被强类型化为 SVGSVGElement。

于 2014-09-04T12:12:31.847 回答
1

您可能需要DOMcompilerOptions.lib您的tsconfig.json.

// 'tsconfig.json'
 {
  "compilerOptions": {
    "target": "ES2017",
    "module": "commonjs",
    "lib": [
      "es5",
      "DOM",
      "esnext"
    ]
  }
}
于 2020-06-29T19:45:00.580 回答
0

这是一个老话题……也许到 2012 年就死了,但对 VS Code 和 typescript 来说是令人兴奋和新的。

我必须执行以下操作才能使其在具有以下包引用的 VS Code 中工作。

const demoCanvas: HTMLCanvasElement = document.getElementById('rfrnCanvas') as any;

        if(demoCanvas.getContext) {
            const context = demoCanvas.getContext('2d');

            if(context) {
                reactangle(context);
            }
        }

打字稿版本:

{
    "@typescript-eslint/eslint-plugin": "^2.29.0",
    "@typescript-eslint/parser": "^2.29.0",
    "typescript": "^3.7.5"
}

于 2020-05-02T01:39:20.027 回答