Html TypeScript:类型系统问题
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13669404/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
TypeScript: problems with type system
提问by lhk
I'm just testing typescript in VisualStudio 2012 and have a problem with its type system. My html site has a canvas tag with the id "mycanvas". I'm trying to draw a rectangle on this canvas. Here's the code
我只是在 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);
Unfortunately VisualStudio complains that
不幸的是 VisualStudio 抱怨说
the property 'getContext' does no exist on value of type 'HTMLElement'
“HTMLElement”类型的值上不存在“getContext”属性
It marks the second line as an error. I thought this would be merely a warning but the code does not compile. VisualStudio says that
它将第二行标记为错误。我认为这只是一个警告,但代码无法编译。VisualStudio 说
there were build errors. Would you like to continue and run the last successful build ?
存在构建错误。您想继续并运行上次成功的构建吗?
I didn't like this error at all. Why is there no dynamic method invocation ? After all the method getContext definitely exists on my canvas element. However I thought this problem would be easy to solve. I just added a type annotiation for canvas:
我根本不喜欢这个错误。为什么没有动态方法调用?毕竟 getContext 方法肯定存在于我的画布元素上。不过我认为这个问题很容易解决。我刚刚为画布添加了一个类型注释:
var canvas : HTMLCanvasElement = document.getElementById("mycanvas");
var ctx: CanvasRenderingContext2D = canvas.getContext("2d");
ctx.fillStyle = "#00FF00";
ctx.fillRect(0, 0, 100, 100);
But the type system still wasn't satisfied. Here's the new error message, this time in the first line:
但是类型系统仍然不满足。这是新的错误消息,这次在第一行:
Cannot convert 'HTMLElement' to 'HTMLCanvasElement': Type 'HTMLElement' is missing property 'toDataURL' from type 'HTMLCanvasElement'
无法将“HTMLElement”转换为“HTMLCanvasElement”:“HTMLElement”类型缺少“HTMLCanvasElement”类型中的“toDataURL”属性
Well, I'm all out for static typing but this makes the language unusable. What does the type system want me to do ?
好吧,我全力支持静态类型,但这使得该语言无法使用。类型系统要我做什么?
UPDATE:
更新:
Typescript has indeed no support for dynamic invocation and my problem can be solved with typecasts. My question is basically a duplicate of this one TypeScript: casting HTMLElement
Typescript 确实不支持动态调用,我的问题可以通过类型转换来解决。我的问题基本上是这个TypeScript的副本:casting HTMLElement
回答by Markus Jarderot
var canvas = <HTMLCanvasElement> document.getElementById("mycanvas");
var ctx = canvas.getContext("2d");
or using dynamic lookup with the any
type (no typechecking):
或使用动态查找any
类型(无类型检查):
var canvas : any = document.getElementById("mycanvas");
var ctx = canvas.getContext("2d");
You can look at the different types in lib.d.ts.
您可以查看lib.d.ts中的不同类型。
回答by Halil Kocaerkek
const canvas = document.getElementById('stage') as HTMLCanvasElement;
回答by Karol Majewski
While other answers promote type assertions (that's what they are — TypeScript doesn't have type caststhat actually change the type; they are merely a way of suppressing type checking errors), the intellectually honest way to approach your problem is to listen to the error messages.
虽然其他答案促进了类型断言(这就是它们的本质——TypeScript 没有实际改变类型的类型转换;它们只是抑制类型检查错误的一种方式),但解决问题的理智诚实的方法是倾听错误信息。
In your case, there are 3 things that can go wrong:
在您的情况下,有 3 件事可能会出错:
document.getElementById("mycanvas")
might returnnull
, because no node of that id is found (it might have been renamed, not injected to the document yet, someone might have tried running your function in an environment without access to DOM)document.getElementById("mycanvas")
might return a reference to a DOM element, but this DOM element is not aHTMLCanvasElement
document.getElementById("mycanvas")
did return a validHTMLElement
, it is indeed anHTMLCanvasElement
, but theCanvasRenderingContext2D
is not supported by the browser.
document.getElementById("mycanvas")
可能会返回null
,因为没有找到该 id 的节点(它可能已被重命名,尚未注入到文档中,有人可能尝试在无法访问 DOM 的环境中运行您的函数)document.getElementById("mycanvas")
可能返回对 DOM 元素的引用,但此 DOM 元素不是HTMLCanvasElement
document.getElementById("mycanvas")
确实返回了一个有效的HTMLElement
,它确实是一个HTMLCanvasElement
,但是CanvasRenderingContext2D
浏览器不支持 。
Instead of telling the compiler to shut up (and possibly finding yourself in a situation where a useless error message like Cannot read property 'getContext' of null
is thrown), I recommend taking control over your application boundaries.
我建议不要让编译器关闭(并且可能会发现自己处于Cannot read property 'getContext' of null
抛出无用错误消息之类的情况),而是建议控制您的应用程序边界。
Make sure the element contains a HTMLCanvasElement
确保元素包含 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;
}
Make sure the rendering context is supported by the browser
确保浏览器支持渲染上下文
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;
}
Usage:
用法:
const ctx: CanvasRenderingContext2D = getCanvasRenderingContext2D(getCanvasElementById('mycanvas'))
ctx.fillStyle = "#00FF00";
ctx.fillRect(0, 0, 100, 100);
回答by Chris
It seems this is being corrected in the .9 version of TypeScript: http://blogs.msdn.com/b/typescript/archive/2013/03/25/working-on-typescript-0-9-generics-overload-on-constants-and-compiler-performance.aspxSee the section on "Overload on Constants" where the canvas tag is explicitly shown.
这似乎在 .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请参阅“常量重载”部分,其中明确显示了画布标记。
回答by Edward
I had the same problem, but with SVGSVGElement instead of HTMLCanvasElement. Casting to SVGSVGElement gave a compile-time error:
我有同样的问题,但使用 SVGSVGElement 而不是 HTMLCanvasElement。转换为 SVGSVGElement 会出现编译时错误:
var mySvg = <SVGSVGElement>document.getElementById('mySvg');
Cannot convert 'HTMLElement' to 'SVGSVGElement':
Type 'HTMLElement' is missing property 'width' from type 'SVGSVGElement'.
Type 'SVGSVGElement' is missing property 'onmouseleave' from type 'HTMLElement'.
无法将“HTMLElement”转换为“SVGSVGElement”:
“HTMLElement”类型缺少“SVGSVGElement”类型中的“width”属性。
类型 'SVGSVGElement' 缺少类型 'HTMLElement' 的属性 'onmouseleave'。
If fixed it by first casting to 'any':
如果通过首先强制转换为“任何”来修复它:
var mySvg = <SVGSVGElement><any>document.getElementById('mySvg');
or this way (it has the identical effect)
或者这样(它具有相同的效果)
var mySvg: SVGSVGElement = <any>document.getElementById('mySvg');
Now mySvg is strongly typed as SVGSVGElement.
现在 mySvg 被强类型化为 SVGSVGElement。
回答by anAgent
This is an old topic... maybe dead to 2012, but exciting and new to VS Code and typescript.
这是一个古老的话题……也许到 2012 年就已经过时了,但是对于 VS Code 和打字稿来说,这是一个令人兴奋的新话题。
I had to do the following to get this to work in VS Code with the following package references.
我必须执行以下操作才能使用以下包引用在 VS Code 中工作。
const demoCanvas: HTMLCanvasElement = document.getElementById('rfrnCanvas') as any;
if(demoCanvas.getContext) {
const context = demoCanvas.getContext('2d');
if(context) {
reactangle(context);
}
}
Typescript Version:
打字稿版本:
{
"@typescript-eslint/eslint-plugin": "^2.29.0",
"@typescript-eslint/parser": "^2.29.0",
"typescript": "^3.7.5"
}