# TypeScript: “Property 'x' does not exist on type 'Y'” (TS2339)

> TS2339: Property does not exist on type. Add it to the type, narrow a union with in or typeof, type the initial state, or augment a global or library type.

Canonical: https://app369.com/fix/typescript-property-does-not-exist-on-type/
Last updated: 2026-11-07

The TypeScript compiler or your editor stops with Property 'name' does not exist on type '{}' (or on type 'Window', 'Request', 'never' or a union). The code reads a property that the type, as TypeScript knows it, does not have. Sometimes the type is wrong, sometimes the code needs to check which kind of value it has first.

**Short answer**

Look at the type named in the message. If it is your own interface, add the property (optional with ? if it is not always there). If it is a union such as Cat | Dog, check which one you have first with 'meow' in pet or typeof before reading the property. If it is {} or never, the variable was typed from an empty initial value: give it a real type, such as useState<User | null>(null). For window.x or Express’s req.user, add the property with a global or module augmentation. Avoid casting to any, which hides real bugs.

## **Why TypeScript doesn’t know the property, and the fix**

1. 01 ### **The property is missing from your type** The interface or type alias does not list the property, or the name is spelled differently from the data. Add it, as optional if the API does not always send it.```
interface User {
  id: string;
  name: string;
  avatarUrl?: string; // optional: some users have none
}
```
2. 02 ### **A union type that has not been narrowed**
  > “JavaScript has an operator for determining if an object or its prototype chain has a property with a name: the in operator.” [**TypeScript, Narrowing: the in operator**](https://www.typescriptlang.org/docs/handbook/2/narrowing.html) With a value typed as A | B, TypeScript only lets you read properties that both have. Check which one you have first, with the in operator, typeof, or a discriminant field, and TypeScript narrows the type inside that branch.```
type Pet = { meow(): void } | { bark(): void };
function speak(pet: Pet) {
  if ('meow' in pet) pet.meow();
  else pet.bark();
}
```
3. 03 ### **The type was inferred from an empty value** const [user, setUser] = useState({}) makes user type {}, and useState([]) makes an array of never, so every property is unknown. Give the state or variable the type it will hold.```
const [user, setUser] = useState<User | null>(null);
const items: Product[] = [];
```
4. 04 ### **A global or library type needs an extra property**
  > “You can also add declarations to the global scope from inside a module” [**TypeScript, Declaration merging: global augmentation**](https://www.typescriptlang.org/docs/handbook/declaration-merging.html) window.dataLayer, a value your own middleware puts on Express’s req (req.user) or a custom field on a library type is not in that library’s types. Declare it once in a .d.ts file that your tsconfig includes, instead of casting at every use.```
// types/global.d.ts
export {};
declare global {
  interface Window { dataLayer: unknown[] }
  namespace Express {
    interface Request { user?: { id: string } }
  }
}
```

Checked against the vendor’s docs on November 7, 2026: [TypeScript Handbook: Narrowing](https://www.typescriptlang.org/docs/handbook/2/narrowing.html); [TypeScript Handbook: Declaration merging (module and global augmentation)](https://www.typescriptlang.org/docs/handbook/declaration-merging.html).

## **Rather hand it over?**

Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.

- [from $450**App Fix Ticket**One reproducible bug in an existing mobile or web app, diagnosed and fixed.**See scope and start**](https://app369.com/fixed-price/flutter-firebase-bug-fix/)
- [from $450**AI-Built App Rescue**A Lovable, Bolt or Cursor app checked end to end in 3 days, then its worst problems fixed at a fixed price.****No issues worth fixing, no charge.**** If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.**See scope and start**](https://app369.com/fixed-price/ai-app-rescue/)

Related: [**“Cannot read properties of undefined”**](https://app369.com/fix/cannot-read-properties-of-undefined/) · [**TypeError: “x is not a function”**](https://app369.com/fix/javascript-is-not-a-function/) · [**Next.js “window is not defined”**](https://app369.com/fix/nextjs-window-is-not-defined/)

Questions

## **More on this error**

<details>

<summary>**Can I just use (obj as any).name? **+</summary>

It silences the error, but it also turns off every check on that value, so a typo or a missing field becomes a runtime crash. Fix the type or narrow the value instead; keep any for rare cases you document.

</details>

<details>

<summary>**Why does it say “on type never”? **+</summary>

TypeScript decided no value can reach that line, usually because an array was typed from [] with no type, or a check already ruled out every case. Type the array, or look at the checks above that line.

</details>

<details>

<summary>**Can you fix it for me? **+</summary>

If one bug is the whole problem, the App Fix Ticket covers it: a written diagnosis first, then the fix. If the app has more going on, the Launch Check is a written check of the whole app. Each issue found is rated critical, high, medium or low, with where it is and how it was confirmed. No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.

</details>

A different error?

## **Describe it and get a written quote**

Send the error and what you were doing. You get a written scope, a fixed price and a timeline; Simon replies by email, usually within one business day.

[**Describe your problem **→](https://app369.com/contact/) [**All fixes**](https://app369.com/fix/)