TypeScript: problems with type system

13 浏览
0 Comments

TypeScript: problems with type system

我只是在VisualStudio 2012中测试TypeScript,并且遇到了它的类型系统的问题。我的HTML网站有一个带有id“mycanvas”的canvas标签。我试图在这个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

0
0 Comments

TypeScript: 类型系统的问题

在其他答案中,提倡使用类型断言(那就是它们的用途 - 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 Playground

0
0 Comments

在上述代码中,我们使用了两种不同的方法来获取canvas元素的上下文对象。第一种方法使用了类型断言<HTMLCanvasElement>,将返回值转换为HTMLCanvasElement类型,然后再调用getContext("2d")方法。第二种方法中,我们将canvas对象的类型声明为any,而不进行类型检查,直接调用getContext("2d")方法。

上述代码的问题在于,第一种方法中的类型断言可能导致类型不匹配的错误。如果我们错误地将一个非HTMLCanvasElement类型的对象转换为HTMLCanvasElement类型,那么在调用getContext("2d")方法时就会出现类型错误。而第二种方法中,由于将canvas对象的类型声明为any,TypeScript将不会对其进行类型检查,因此无法发现类型错误。

解决这个问题的方法是,应该尽量避免使用类型断言来进行类型转换,而是使用更准确的类型声明。对于获取canvas上下文对象,推荐使用CanvasRenderingContext2D类型来声明canvas对象的类型。在TypeScript 1.8及以后的版本中,.getContext("2d")方法会根据常量字符串参数"2d"来自动推断返回类型为CanvasRenderingContext2D,因此不需要显式地进行类型转换。

为了避免类型错误,我们应该尽量避免使用类型断言进行类型转换,而是使用准确的类型声明,特别是在获取canvas上下文对象时。使用CanvasRenderingContext2D类型声明canvas对象的类型可以让TypeScript在编译时进行类型检查,以提前发现并修复类型错误。

0
0 Comments

问题出现的原因是在TypeScript中,getElementById方法返回的是HTMLElement类型,而不是HTMLCanvasElement类型。因此,需要使用类型断言(as)将返回值转换为HTMLCanvasElement类型。

解决方法是在获取元素的同时使用类型断言将其转换为正确的类型,如下所示:

const canvas = document.getElementById('stage') as HTMLCanvasElement;

这样,我们就可以在后续的代码中使用canvas变量,并且TypeScript会将其类型识别为HTMLCanvasElement类型,从而避免类型错误的问题。

以上是关于(TypeScript: problems with type system)问题的出现原因以及解决方法的整理。

0