我只是在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);
不幸的是,VisualStudio抱怨说
“HTMLElement”类型的值上不存在属性“getContext”
它将第二行标记为错误。我认为这只是一个警告,但代码不编译。 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);
但是类型系统仍然不满意。这是新的错误消息,这次是在第一行:
无法将'HTMLElement'转换为'HTMLCanvasElement':类型'HTMLElement'缺少类型'HTMLCanvasElement'的属性'toDataURL'
好吧,我全力以赴静态打字,但这使语言无法使用。类型系统要我做什么?
更新:
Typescript确实不支持动态调用,我的问题可以通过类型转换来解决。我的问题基本上是这个TypeScript: casting HTMLElement的重复
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中的不同类型。
const canvas = document.getElementById('stage') as HTMLCanvasElement;
似乎这在.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请参阅“常量过载”部分,其中明确显示了canvas标记。
我有同样的问题,但使用SVGSVGElement而不是HTMLCanvasElement。转换为SVGSVGElement会产生编译时错误:
var mySvg = <SVGSVGElement>document.getElementById('mySvg');
无法将'HTMLElement'转换为'SVGSVGElement': 类型'HTMLElement'缺少类型'SVGSVGElement'的属性'width'。 类型'SVGSVGElement'缺少类型'HTMLElement'的属性'onmouseleave'。
如果通过首先转换为'any'来修复它:
var mySvg = <SVGSVGElement><any>document.getElementById('mySvg');
或者这样(它有相同的效果)
var mySvg: SVGSVGElement = <any>document.getElementById('mySvg');
现在mySvg被强类型化为SVGSVGElement。
虽然其他答案促进类型断言(这就是它们是什么 - 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);