TypeScript: ปัญหาเกี่ยวกับระบบประเภท


102

ฉันเพิ่งทดสอบ typescript ใน VisualStudio 2012 และมีปัญหากับระบบประเภท ไซต์ html ของฉันมีแท็ก canvas ที่มี id "mycanvas" ฉันกำลังพยายามวาดรูปสี่เหลี่ยมผืนผ้าบนผืนผ้าใบนี้ นี่คือรหัส

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

น่าเสียดายที่ 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);

แต่ระบบประเภทยังไม่เป็นที่พอใจ นี่คือข้อความแสดงข้อผิดพลาดใหม่ในครั้งนี้ในบรรทัดแรก:

ไม่สามารถแปลง 'HTMLElement' เป็น 'HTMLCanvasElement': ประเภท 'HTMLElement' ไม่มีคุณสมบัติ 'toDataURL' จากประเภท 'HTMLCanvasElement'

ฉันหมดแล้วสำหรับการพิมพ์แบบคงที่ แต่ทำให้ภาษาใช้ไม่ได้ ระบบประเภทต้องการให้ฉันทำอะไร?

อัพเดท:

typescript ไม่รองรับการเรียกแบบไดนามิกและปัญหาของฉันสามารถแก้ไขได้ด้วยตัวพิมพ์ คำถามของฉันโดยทั่วไปซ้ำกับTypeScriptนี้: การหล่อ HTMLElement

คำตอบ:


225
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


9
เป็นมูลค่าการกล่าวขวัญว่าควรใช้CanvasRenderingContext2Dแทนanyประเภทสำหรับบริบทผ้าใบ
Ivan Kochurkin

3
ตั้งแต่ typescript 1.8 ก็จะรับรู้อาร์กิวเมนต์สตริงอย่างต่อเนื่อง"2d"และจะกลับมาพร้อมกับชนิด.getContext("2d") CanvasRenderingContext2Dคุณไม่จำเป็นต้องแคสต์อย่างโจ่งแจ้ง
Markus Jarderot

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

7
โปรดอธิบายว่าเหตุใดรหัสนี้จึงช่วยแก้ปัญหาของ OP แทนที่จะเป็นเพียงคำตอบของรหัส โค้ดของคุณทำอะไรแตกต่างกันอย่างไรช่วยอย่างไร

คุณคัดลอก / วางและใช้งานได้ มีอะไรจะอธิบายที่นี่? หากไม่ได้ผลสำหรับคุณคุณควรอธิบายปัญหาของคุณและถามเฉพาะเจาะจงมากขึ้น
lenooh

7

ในขณะที่คำตอบอื่น ๆ จะส่งเสริมการยืนยันประเภท (นั่นคือสิ่งที่เป็น - 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 สนามเด็กเล่น



1

ฉันมีปัญหาเดียวกัน แต่ใช้ SVGSVGElement แทน HTMLCanvasElement การส่งไปยัง SVGSVGElement ทำให้เกิดข้อผิดพลาดเวลาคอมไพล์:

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

ไม่สามารถแปลง 'HTMLElement' เป็น 'SVGSVGElement':
ประเภท 'HTMLElement' ไม่มีคุณสมบัติ 'width' จากประเภท 'SVGSVGElement'
ประเภท 'SVGSVGElement' ไม่มีคุณสมบัติ 'onmouseleave' จากประเภท 'HTMLElement'

หากแก้ไขโดยการส่งครั้งแรกเป็น "ใด ๆ ":

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

หรือด้วยวิธีนี้ (มีผลเหมือนกัน)

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

ตอนนี้ mySvg ถูกพิมพ์อย่างรุนแรงว่า SVGSVGElement


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:

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.