Learn why TypeScript throws TS1136 when an object literal contains a stray comma, operator or decorator, and how to clean it up.
TS1136 means the TypeScript parser was reading an object literal, expected the next thing to be a property, and found something that cannot start one. The compiler message is short and a little abstract — Property assignment expected. — but the caret is precise: it points at the exact token that does not belong.
This happens during parsing, before any type checking. No compiler option changes it: strict, target, module and skipLibCheck are all irrelevant, because the file cannot be turned into a syntax tree in the first place. Inside { … } the parser accepts only four shapes — key: value, shorthand key, a method or accessor, and ...spread — and anything else lands here.
In practice TS1136 is an editing leftover rather than a design mistake. You deleted a property and its comma stayed behind; you reordered lines and a comma floated to the top; you removed a key but left the expression that used to follow it. Because the parser gives up on the rest of the literal, TS1136 almost always drags a cascade of follow-up errors with it — typically TS1128: Declaration or statement expected. on the closing brace. Fix the TS1136 and the cascade disappears.
// The general shape of the error:
const shippingOrigin = { latitude: 48.137,, longitude: 11.575 }
// ~ Error: Property assignment expected.This is by far the most common trigger. You delete a line from an object literal — or comment it out — and its trailing comma survives on its own, so the parser reaches a comma where it wanted the next key.
// ❌ Broken — the `altitude` line is gone, its comma is not
const shippingOrigin = {
latitude: 48.137,
,
longitude: 11.575
}
//~ Error: Property assignment expected. (plus TS1128 on the closing brace)// ✅ Fixed — delete the orphaned separator too
const shippingOrigin = {
latitude: 48.137,
longitude: 11.575
}Commenting a property out has exactly the same effect if the comma sits outside the comment. // altitude: 519 followed by a lone , on the next line is still a doubled separator as far as the parser is concerned.
A comma can also drift to the front of a literal — after reordering properties, after a bad merge, or after deleting the first entry of a comma-first formatted object. Nothing can precede the first property, so the parser stops immediately.
// ❌ Broken — the first property was removed, the comma stayed
const requestHeaders = {
, accept: "application/json",
authorization: `Bearer ${accessToken}`
}
//~ Error: Property assignment expected.// ✅ Fixed — the first entry needs no separator in front of it
const requestHeaders = {
accept: "application/json",
authorization: `Bearer ${accessToken}`
}The same thing happens right after a spread: { ...baseHeaders, , timeoutMs: 5000 } reports TS1136 at the second comma. A spread is a full member, so it is separated from the next property by exactly one comma, like everything else.
= Where the Key BelongsIf you delete a property name but keep the expression that belonged to it, the literal now starts a member with an operator. =, +, -, ! and friends can never open a property.
// ❌ Broken — `grandTotal: netTotal` was deleted, the rest of the sum stayed
const invoiceSummary = {
itemCount: 3,
+ taxTotal
}
//~ Error: Property assignment expected.// ✅ Fixed — give the value a key again
const invoiceSummary = {
itemCount: 3,
grandTotal: netTotal + taxTotal
}A stray = reads the same way: { itemCount: 3, = netTotal } reports TS1136 at the equals sign. Note that = after a name is a different diagnostic — { itemCount = 0 } gives TS1312, which tells you to use a colon instead.
Decorators are a class feature. Putting @observable, @Input() or any other decorator inside a plain object literal is a syntax error in both the legacy and the standard decorator implementations, and the parser reports it at the at-sign.
// ❌ Broken — decorators cannot appear in an object literal
const cartStore = {
@observable itemCount: 0,
currency: "EUR"
}
//~ Error: Property assignment expected. (plus TS1146 and TS1128)// ✅ Fixed — a plain object needs no decorator
const cartStore = {
itemCount: 0,
currency: "EUR"
}If you actually need the decorator's behaviour, move the state onto a class, which is a valid decorator target. Assuming observable comes from your state library:
// ✅ Fixed — decorators belong on class members
class CartStore {
@observable itemCount = 0
currency = "EUR"
}MobX also accepts a plain object directly — observable({ itemCount: 0, currency: "EUR" }) — which keeps the literal decorator-free. This pattern is a frequent casualty of Babel-to-TypeScript migrations, where class-property syntax gets pasted into an object by accident.
Look at the token the caret points at, not the whole literal. TS1136 is reported at the offending character. Nine times out of ten it is a comma, an = or an @, and deleting that single token fixes the file.
Scan for doubled and leading commas first. Search the literal for ,,, for a comma on a line of its own, and for a comma immediately after the opening brace. A trailing comma before } is legal and is never the problem.
Ignore the follow-up errors until the TS1136 is gone. The parser abandons the literal at the bad token, so one TS1136 usually produces a TS1128 on the closing brace and sometimes a TS1005 further along. Fix the first error and recompile before reading the rest.
Run Prettier on the file. A formatter cannot parse broken syntax either, and it reports the position it choked on — a fast second opinion when the literal is long or deeply nested. If Prettier reformats the file without complaint, the braces you are staring at are not the ones with the problem.
Check whether the braces were meant to be an object at all. An arrow function returning an object literal needs parentheses — () => ({ total: 0 }). A type literal is not an object literal: modifiers and signatures that are legal in a type or interface body are not legal inside { } in an expression, and the type-literal twin of this error is TS1131.
Let the editor keep it from recurring. Deleting a whole line with your editor's line-delete command (rather than selecting the text) removes the comma with it, and turning on format-on-save surfaces a stray separator the moment you introduce it.
TS1136 is a parser error raised inside an object literal. The parser accepts exactly four kinds of member — key: value, a shorthand key, a method or accessor, and ...spread — and when the next token cannot begin any of them, it reports Property assignment expected. at that token.
The usual culprits are a doubled comma, a comma at the very start of the literal, an operator such as = or + left behind after a key was deleted, and a decorator. Because the error is syntactic, it fires regardless of your tsconfig.json: no strict setting, target or lib changes it.
No — and this is worth pinning down, because several popular write-ups claim otherwise. A missing comma between two properties produces TS1005 with the message ',' expected, and a bare string key like { "Content-Type" } produces TS1005 with ':' expected. Verified against TypeScript 5.3: neither emits TS1136.
TS1136 is the opposite failure — one separator too many, or a token that is not a property at all. A trailing comma before the closing brace, as in { retries: 2, }, is valid JavaScript and valid TypeScript and never produces either error.
No. Decorators attach to class declarations and class members only. That restriction holds for the legacy experimentalDecorators implementation and for the standard ECMAScript decorators that became the default in TypeScript 5.0 — the grammar simply has no production for a decorated object-literal property, so you get TS1136 at the @ followed by a cascade of parse errors.
The fix depends on what you were after. If you wanted MobX-style observability, either move the fields onto a class and decorate them there, or pass the plain object to observable(). If you were porting Angular or NestJS code, remember those decorators only ever worked on classes and their members in the first place.
Browse all TypeScript practice challenges to keep sharpening your type-level skills.
Track your progress through 200+ hands-on challenges. Free, sign in with GitHub.
Or start solving right away: explore all TypeScript challenges