241

I have added TS to my React/Redux app.

I use window object in my app like this:

componentDidMount() {
  let FB = window.FB;
}

TS throws an error:

TypeScript error: Property 'FB' does not exist on type 'Window'. TS2339

I want to fix the error.

1 (doesn't work)

// Why doesn't this work? I have defined a type locally

type Window = {
  FB: any
}

componentDidMount() {
  let FB = window.FB;
}

// TypeScript error: Property 'FB' does not exist on type 'Window'. TS2339

2 (fixes the error)

I found the answer here https://stackoverflow.com/a/56402425/1114926

declare const window: any;

componentDidMount() {
  let FB = window.FB;
}
// No errors, works well

Why doesn't the first version work, but the second does, even though I do not specify FB property at all?

Green
  • 28,742
  • 61
  • 158
  • 247

11 Answers11

453

Why does declare const window: any; work?

Because you declare a local variable of type any. Having something of type any essentially turns off type checking for window so you can do anything with it. I really do not recommend this solution, it is a really bad one.

Why doesn't type Window = { FB: any } work? You define a type Window. This type if defined in a module has nothing to do with the type of the global window object, it is just a type that happens to be called Window inside your module.

The good solution To extend window you must extend the global Window interface. You can do this like this:

declare global {
    interface Window {
        FB:any;
    }
}

let FB = window.FB; // ok now

Note that this extension is going to be available in your whole project not just the file you define it in. Also if FB has definitions you might consider typing it a bit better (FB: typeof import('FBOrWhateverModuleNameThisHas'))

PPC-Coder
  • 3,522
  • 2
  • 21
  • 30
Titian Cernicova-Dragomir
  • 230,986
  • 31
  • 415
  • 357
  • 26
    Your "good solution" doesn't compile."Property FB does not exist on type window & typeof globalThis" – jtiscione Jul 25 '20 at 21:12
  • 28
    @jtiscione yes it does https://www.typescriptlang.org/play?noImplicitReturns=false#code/KYDwDg9gTgLgBAbwL4CgAmwDGAbAhlYOAc2wgCNdtEU5a4BLAOxmCgDNdNCB1JtCAO7U6IuADEAQgC5cjAJ4BuGnVRI4KFNmDxJcALxwBfQQDpJCuAHpLcCAGs4jQUA if your file is not a module, remove the declare global https://www.typescriptlang.org/play?noImplicitReturns=false#code/JYOwLgpgTgZghgYwgAgOqgCYHsDuyDeAUMsgGIBCAXHCAJ4DchAvoQDYRhnnIC8yOmXADoK9ZAHpxyLAGtkIXEA – Titian Cernicova-Dragomir Jul 25 '20 at 22:34
  • 4
    Why is this answer not marked as the Answer? I looked long and far to find a method to access reactive state functions from the console/external JS and this is the only one that compiled in TS and worked – Beerswiller May 20 '21 at 01:58
  • 3
    @Beerswiller Because the OP couldn't get it to work and didn't bother to follow up ‍♂️ – Titian Cernicova-Dragomir May 20 '21 at 06:03
  • 1
    If admins cared about the quality of the content on this site, they would take over this derelict question and accept an answer. – Andrew Koster Aug 31 '21 at 17:16
  • This doesn't work: Top-level declarations in .d.ts files must start with either a 'declare' or 'export' modifier. – Kevin Toet Feb 01 '22 at 23:30
  • 5
    If anyone is struggling with this answer on angular, put this code ```declare global { interface Window { FB:any; } }``` inside main.ts – Luiz Mar 29 '22 at 13:51
  • @Luiz Can anyone correct this code – Varun Sharma Mar 31 '22 at 18:53
  • @VarunSharma is the same code of the answer, but without the let FB = window.FB part – Luiz Mar 31 '22 at 19:05
  • Putting it inside the main entry "main.ts" make it work, but why? why having it inside a global.d.ts doesn't work? – shamaseen Nov 08 '22 at 21:17
  • ok, I figure it out, you need to put `export {};` in the `*.d.ts` file in order for the compiler to read it. – shamaseen Nov 08 '22 at 21:20
  • If anyone is doing this with Typescript, this link may help you. https://www.devextent.com/create-service-worker-typescript/ – Balasubramani M Mar 17 '23 at 09:32
70

There are a few ways to solve this problem.

Some examples:

1-) Do a cast

(window as any).X

2-) Put the following code in a file named react-app-env.d.ts

interface Window {
  X?: {
    Y?: {
      .......
    }
  }
}
Chris Pavs
  • 85
  • 5
28

you can solve the problem easily without any need to declaration

window["FB"]

UPDATE
since it's a workaround without any compiler configuration to ensure your program's compatibility with typescript maybe you will need just a type validation.

if(window["FB"]) {
  // do some FB logic
}
S.Saderi
  • 4,755
  • 3
  • 21
  • 23
  • 3
    That didn't work, it says `TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'.` – shamaseen Nov 08 '22 at 20:58
  • @shamaseen this is the fastest way to solve the problem if you have specific type for index, you can use Titian's solution – S.Saderi Nov 10 '22 at 18:04
  • If you get the `TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'` message, the following `tsconfig.json` property/value can be used to suppress it: `"suppressImplicitAnyIndexErrors": true` – A-Diddy Dec 29 '22 at 01:13
  • 2
    Don't suppress errors. The point of TypeScript is to catch errors like this. – Jimmy Jan 29 '23 at 07:28
14

I use this without declare global

declare const window: Window &
   typeof globalThis & {
     FB: any
   }
Michal Frystacky
  • 1,418
  • 21
  • 38
Hugo Laguna
  • 165
  • 1
  • 4
9

HACK SOLUTION for problem "Property does not exist on type Window in TypeScript"

STEP:1 In your src directory, create a types directory that contains the following index.d.ts file: src/types/index.d.ts

export {};

declare global {
  interface Window {
    example: string; // whatever type you want to give. (any,number,float etc)
  }
}

STEP: 2 add the path to your types directory to your tsconfig.json file.

tsconfig.json

{
  "compilerOptions": {
    // ... rest
    "typeRoots": ["./node_modules/@types", "./src/types"]
  }
}

STEP: 3 Now use it, whereever you want to do it.

window.example = 'hello';

console.log(window.example);
Jamal Ashraf
  • 569
  • 6
  • 9
  • 1
    Why do you consider this a "HACK SOLUTION"? – Fatedx Jan 02 '23 at 18:27
  • 1
    @Fatedx it works really well! i was messing around with so many things but this worked really well so i just said HACK SOLUTION because it resolved the problem. :) – Jamal Ashraf Jan 03 '23 at 16:14
8

I was facing this issue in my angular code. Below solution helped me to resolve the issue.

I resolved this error by creating a folder name types inside src and inside that folder created index.d.ts file.

the index.d.ts file will have below code.

export {};
declare global {
  interface Window {
    chrome: any;  // this will be your variable name
  }
}

If the error persists, try adding the path to your types directory to your tsconfig.json file.

{
  "compilerOptions": {
    // ... rest
    "typeRoots": ["./node_modules/@types", "./src/types"]
  }
}
5

better still

declare global {
  interface Window {
    FB: {
      CustomerChat: {
        hide: () => void;
        show: () => void;
      };
    };
  }
}
kyun
  • 9,710
  • 9
  • 31
  • 66
bitotm
  • 49
  • 2
  • 1
  • 2
    As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Oct 13 '21 at 06:37
3

it should be ignored by creating global.d.ts file in root of project with this content:

export { }
declare global {
    interface Window {
        [key: string]: any 
    }
}

it ignores all variables of window object

Saeid Doroudi
  • 935
  • 1
  • 9
  • 25
2

This worked for me without declaring it globally

declare const window: Window &
   typeof globalThis & {
     FB: any
   }

This was the error I was facing Error: Property 'name' does not exist on type '{}'.ts(2339) Although mine wasn't really related with your code but this guide should help you

Justice
  • 51
  • 3
0

For anyone coming from Next.Js, you need to use <Script /> inside of <body> to load it (loading it inside of the <Head /> won't work):

https://nextjs.org/docs/basic-features/script

a7dc
  • 3,323
  • 7
  • 32
  • 50
0

Use a temp variable and cast it to any

const tempWindow: any = window;
const anyProperty = tempWindow.anyProperty;
KISHORE K J
  • 186
  • 2
  • 4