TypeScript:类型系统的问题

lhk*_*lhk 88 html5 types static-typing web typescript

我只是在VisualStudio 2012中测试打字稿并且它的类型系统有问题.我的html网站有一个带有id"mycanvas"的canvas标签.我正试图在这个画布上画一个矩形.这是代码

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

不幸的是,VisualStudio抱怨说

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

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

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

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

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

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

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

好吧,我全力以赴静态打字,但这使语言无法使用.类型系统要我做什么?

更新:

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

Mar*_*rot 199

var canvas = <HTMLCanvasElement> document.getElementById("mycanvas");
var ctx = canvas.getContext("2d");
Run Code Online (Sandbox Code Playgroud)

或者使用any类型的动态查找(没有类型检查):

var canvas : any = document.getElementById("mycanvas");
var ctx = canvas.getContext("2d");
Run Code Online (Sandbox Code Playgroud)

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

  • 值得一提的是,对于画布上下文,最好使用`CanvasRenderingContext2D`而不是`any`类型. (4认同)
  • 从TypeScript 1.8开始,它将识别常量字符串参数`"2d"`,而`.getContext("2d")`将返回类型为"CanvasRenderingContext2D"的字符串.您不需要显式地强制转换它. (3认同)

Kar*_*ski 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;
}
Run Code Online (Sandbox Code Playgroud)

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

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;
}
Run Code Online (Sandbox Code Playgroud)

用法:

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

ctx.fillStyle = "#00FF00";
ctx.fillRect(0, 0, 100, 100);
Run Code Online (Sandbox Code Playgroud)

请参阅TypeScript Playground


小智 6

const canvas =  document.getElementById('stage') as HTMLCanvasElement;
Run Code Online (Sandbox Code Playgroud)

  • 请解释为什么此代码有助于解决OP的问题,而不仅仅是代码答案。您的代码有何不同之处,有什么帮助? (2认同)