TypeScript : 유형 시스템 문제


101

VisualStudio 2012에서 typescript를 테스트하고 있으며 유형 시스템에 문제가 있습니다. 내 HTML 사이트에는 ID가 "mycanvas"인 캔버스 태그가 있습니다. 이 캔버스에 직사각형을 그리려고합니다. 다음은 코드입니다.

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가 내 캔버스 요소에 확실히 존재합니다. 하지만이 문제는 해결하기 쉬울 것이라고 생각했습니다. 캔버스에 대한 유형 설명을 추가했습니다.

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는 실제로 동적 호출을 지원하지 않으며 내 문제는 typecast로 해결할 수 있습니다. 내 질문은 기본적 으로이 TypeScript 의 복제본입니다 .HTMLElement 캐스팅

답변:


224
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
캔버스 컨텍스트 CanvasRenderingContext2Dany유형 대신 사용 하는 것이 더 낫다는 점을 언급 할 가치가 있습니다.
Ivan Kochurkin 2014 년

3
타이프 라이터 1.8 있기 때문에, 상수 문자열 인수를 인식 "2d"하고, .getContext("2d")종류에 반환됩니다 CanvasRenderingContext2D. 명시 적으로 캐스트 할 필요가 없습니다.
마르쿠스 Jarderot

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

7
이 코드가 코드 답변이 아닌 OP 문제를 해결하는 데 도움이되는 이유를 설명해주세요. 코드가 다르게 수행하는 것은 무엇이며 어떻게 도움이됩니까?

복사 / 붙여 넣기하면 작동합니다. 여기서 설명 할 것은 무엇입니까? 그것이 당신에게 효과가 없다면, 당신 은 당신의 문제를 설명하고 더 구체적으로 물어봐야합니다.
lenooh

6

다른 답변은 유형 어설 션을 장려하지만 (그것이 바로 TypeScript에는 유형 을 실제로 변경하는 유형 캐스트 가 없습니다 . 유형 검사 오류를 억제하는 방법 일뿐입니다) 문제에 접근하는 지적으로 정직한 방법은 오류 메시지.

귀하의 경우 잘못 될 수있는 세 가지가 있습니다.

  • 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를 참조하십시오 .



1

나는 같은 문제가 있었지만 HTMLCanvasElement 대신 SVGSVGElement를 사용했습니다. 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로 강력하게 입력됩니다.


0

이것은 오래된 주제입니다 ... 2012 년까지는 죽었을 수도 있지만 VS Code 및 typescript에는 흥미롭고 새로운 것입니다.

다음 패키지 참조를 사용하여 VS 코드에서 작동하도록하려면 다음을 수행해야했습니다.

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"
}

0

당신은 추가해야 할 수 있습니다 DOMcompilerOptions.lib당신에 tsconfig.json.

// 'tsconfig.json'
 {
  "compilerOptions": {
    "target": "ES2017",
    "module": "commonjs",
    "lib": [
      "es5",
      "DOM",
      "esnext"
    ]
  }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.