TypeScript error

TS2339: A property the type does not have

  • Error TS2339
  • Tested with TypeScript 5.9

error TS2339: Property 'dataLayer' does not exist on type 'Window & typeof globalThis'. is reported when code reads or writes a property that the value's type does not declare. When a declared property has a similar name, the checker reports TS2551 and suggests it instead.

JavaScript files get one allowance TypeScript files do not: assigning a property to an object literal declared in the same file declares the property, so building an object up line by line works. Reading a property nothing declared still fails, and so does adding one to window or to an object whose type comes from a JSDoc annotation.

At a glance

CodeTS2339
MessageProperty '{0}' does not exist on type '{1}'.
TypeScript's categoryerror
Listed underUnknown names and members
Turned on by No option: every checked file reports it
In .js files Reported when the file is checked: checkJs in jsconfig.json, or // @ts-check at the top of the file

The message is TypeScript's own text from its diagnostic messages file (Apache-2.0); {0} and {1} are filled in by tsc for each error.

What it looks like

tracking.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: tracking.js(2,8): error TS2339: Property 'dataLayer' does not exist on type 'Window & typeof globalThis'. tracking.js(6,28): error TS2339: Property 'host' does not exist on type '{ port: number; }'. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. tracking.js(2,8): error TS2339: Property 'dataLayer' does not exist on type 'Window & typeof globalThis'. tracking.js(6,28): error TS2339: Property 'host' does not exist on type '{ port: number; }'. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. tracking.js(2,8): error TS2339: Property 'dataLayer' does not exist on type 'Window & typeof globalThis'. tracking.js(6,28): error TS2339: Property 'host' does not exist on type '{ port: number; }'. checked 21 October 2026
window.dataLayer.push({ event: "add_to_cart" });error TS2339: Property 'dataLayer' does not exist on type 'Window & typeof globalThis'.

const config = { port: 3000 };
export const host = config.host ?? "localhost";error TS2339: Property 'host' does not exist on type '{ port: number; }'.
A property the type does not declare, on window and on a config object.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}

What causes it

  • A global object (window, document, globalThis) is given a property by a third-party script, and the DOM types do not list it.
  • The object's type comes from an annotation or an initializer that does not include the property (config.host when the object was { port: 3000 }).
  • The name is a typo that is too far from any declared name for a suggestion. This happens most with short names: response.josn() gets TS2339, not a hint for json.

How to fix it

Declare the property where the type is defined

For window, add an interface Window { ... } block to a .d.ts file the config includes; it merges with the DOM's own Window. For your own objects, add the property to the @typedef or the inline @type, optional if it may be absent.

tracking.js TypeScript 5.9.3 TypeScript 5.9.3, run 21 October 2026: No errors. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. No errors. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. No errors. checked 21 October 2026
window.dataLayer.push({ event: "add_to_cart" });

/** @type {{ port: number, host?: string }} */
const config = { port: 3000 };
export const host = config.host ?? "localhost";
Declare the property on Window, and give the object a type that has it.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js", "*.d.ts"]
}

Build the object in the same file

In a .js file, an object literal is open-ended: const user = {}; user.name = "Ada"; declares name. A @type annotation on the declaration closes it again.

user.js TypeScript 5.9.3 TypeScript 5.9.3, run 21 October 2026: No errors. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. No errors. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. No errors. checked 21 October 2026
const user = {};
user.name = "Ada";
user.joined = new Date();

export const greeting = `Hello, ${user.name}`;
In a .js file, assigning a property declares it.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}

Same idea, different API

Code written for one API often meets another's types. res.statusCode belongs to Node's http response; the fetch Response has status instead. TS2339 on a name you are sure exists usually means the value is a different kind of object than you think: hover over it to see its type.

Gotchas

  • A property that exists only on some members of a union is TS2339 until the value is narrowed, for example with "items" in value or a check on a shared kind property.
  • globalThis.something is reported as TS7017 instead under noImplicitAny, when no file assigns it.

Sources

Last reviewed 20 October 2026.