3

I want to set the CanvasRenderingContext2D context properties with given Object. But it always throws:

element implicitly has an 'any' type because type '{0}' has no index signature

How can I resolve this problem?

interface Attr {
  fillStyle: string | CanvasGradient | CanvasPattern;
  font: string;
  globalAlpha: number;
  lineCap: string;
  lineWidth: number;
  lineJoin: string;
  miterLimit: number;
  shadowBlur: number;
  shadowColor: string;
  strokeStyle: string;
  textAlign: string;
  textBaseline: string;
  lineDash: string;
}

const element: HTMLCanvasElement = <HTMLCanvasElement>document.querySelector('#c');
const ctx: CanvasRenderingContext2D = element.getContext('2d');

let attr:Partial<Attr> = {
  fillStyle: 'red',
  globalAlpha: 0.8
}

function setAttrs(target: CanvasRenderingContext2D, attr: Partial<Attr>) {
  for (let p in attr) {
    target[p] = attr[p];
  }
}

VS Screenshot vscode shortcut here

msanford
  • 11,803
  • 11
  • 66
  • 93
ray0324
  • 61
  • 1
  • 3
  • 6
  • it's because `CanvasRenderingContext2D` does not have any index signature like `[key:string]: string | number` associated with it . and you are trying to access the properties through index key of type `any` . you need to add index definition like in this question https://stackoverflow.com/questions/42193262/element-implicitly-has-an-any-type-because-type-window-has-no-index-signatur/42193905 – Niladri Mar 28 '18 at 09:37

1 Answers1

12

For Typescript, you can't access the property of CanvasRenderingContext2D by index. Your object Attr is not accessible by index neither, so in fact you have 2 errors: target[p] is invalid, AND attr[p] is also invalid. When I say invalid, it's because the calls target[p] and attr[p] return a variable implicitly typed as any, which is invalid because you have the flag noImplicitAny set to true in tsconfig.json.

You can fix your interface, by adding the index signature [key:string]: any;, but you can't fix CanvasRenderingContext2D.

First solution

Desactivate the compiler rule by setting noImplicitAny to false. In tsconfig.json:

{
  "compilerOptions": {
    "noImplicitAny": false
  }
}

Second solution

Set the flag suppressImplicitAnyIndexErrors to true. In tsconfig.json:

{
  "compilerOptions": {
    "noImplicitAny": true,
    "suppressImplicitAnyIndexErrors": true
  }
}

Third solution

Set everything explicitly. My preferred solution because it preserved typings:

function setAttrs(target: CanvasRenderingContext2D, attr: Partial<Attr>) {
    target.fillStyle = attr.fillStyle;
    target.font = attr.font;
    target.globalAlpha = attr.globalAlpha;
    ...
}

This way you are gaining the full type coverage, which is better!

References:

Cyril Gandon
  • 16,830
  • 14
  • 78
  • 122