I recently converted a TypeScript (TS) class into plain JavaScript (JS), and I ran into one of the most confusing yet common errors:
; expected
or Expression expected
At first, I thought I must have missed a semicolon somewhere but it turned out to be something else entirely.
In this article, I’ll walk you through what caused the error, how I fixed it, and how you can avoid the same mistake when converting TS to JS.
Where the Problem Start
I began by copying my TypeScript code into a .js
file, assuming it would “just work” if I removed the type annotations.
Here’s the original TS code I was working with:
export class ModelEnvironment {
/**
* @param filePath File path of the model.json
* @param shader Shader ("Standard"|"OpaqueLight"|"TransparentLight")
* @param materialName Name of the material used (Will add a number to the end if multiple colors)
* @param color
*/
constructor(filePath: string, shader: shaderType, materialName: string, color: vec3) {
const model = JSON.parse(Deno.readTextFileSync(filePath))
let matNum = 1
const objs = model.objects;
const colors: vec3[] = []
objs.forEach((x: {
position: vec3,
rotation: vec3,
scale: vec3,
shape: geoShape,
color: vec3
}) => {
if (!colors.includes(x.color)) {
colors.push(x.color);
}
new Environment()
.geometry()
.shape(x.shape)
.material(materialName)
.pos(x.position)
.rot(x.rotation)
.scale(x.scale)
.push();
})
colors.forEach((x: vec3) => {
let matName = materialName
if (x.length > 1) matName = `${materialName + matNum}`
new Material(matName)
.color(color)
.shader(shader)
.push();
matNum++;
})
}
}
My Broken JavaScript Conversion
When I rewrote the forEach
callback, I mistakenly did this:
objs.forEach(x => {
position: x.position
rotation: x.rotation
scale: x.scale
shape: x.shape
color: x.color
}) => { // Unexpected arrow!
This is where the dreaded ; expected
error appeared.
Why This Error Happens
It turns out there were two major mistakes:
- The arrow function is malformed. You can’t close a function and then randomly add
=>
again. - Inside an arrow function block, lines like
position: x.position
are treated as labels, not assignments or key-value pairs.
JavaScript only understands that syntax inside an object literal, like { position: x.position }
.
The Correct JavaScript Version
Here’s the fixed and working JS code:
class geoScene {
constructor(filePath, shader, matName, color) {
const model = JSON.parse(fs.readFileSync(filePath))
let matNum = 1
const objs = model.objects;
const colors = []
objs.forEach(x => {
if (!colors.includes(x.color)) {
colors.push(x.color)
}
new Environment()
.geometry()
.shape(x.shape)
.material(matName)
.pos(x.position)
.rot(x.rotation)
.scale(x.scale)
.push()
})
colors.forEach(col => {
let currentName = matName
if (col.length > 1) currentName = `${matName}${matNum}`
new Material(currentName)
.color(color)
.shader(shader)
.push()
matNum++
})
}
}
Add Debug Logging for Practice
To make the code easier to understand while converting from TS to JS, I added some logs:
console.log("Loaded objects:", objs.length);
console.log("Unique Colors Found:", colors);
That way, I could visually confirm that my data was being processed correctly.
Final Thought
Converting TypeScript to JavaScript isn’t always a simple copy-and-paste job especially when arrow functions and type annotations are involved. What looks valid in TS can easily turn into confusing syntax errors in JS. The key lesson I learned is to slow down and clean up TS-specific syntax instead of assuming JavaScript will “figure it out.” Now that I understand why errors like ; expected
happen, I can spot and fix them instantly. If you’re facing similar issues, don’t get discouraged every error is just JavaScript’s way of teaching you something new.