#1739·terser

Inconsistent behavior when filtering out redundant inner-block variable assignment

Author: PecacheuCreated Sep 15, 2026Updated Sep 15, 2026

Hi, I think I found a small edge-case bug in Terser (v5.51.2) with unsafe enabled. I am using Typescript and had some code blocks where I was using variable assignment to narrow down types, expecting Terser to filter that code out at runtime, as in JS it is basically redundant, assigning a const to another const. (It can't ever be something weird like a property accessor, afaik, since it is a direct assignment) But I found out that in some cases, Terser correctly filters these out, but in other cases, it doesn't.

Example of what I'm doing:

typescript
function someMethod(input: DataType) {
	const data: WiderType = input.data;
	if(someRuntimeCondition) {
		const knownData = data as NarrowType; //Terser unsafe should vaporize this code from the mortal realm, but sometimes doesn't?
		doStuff(knownData.propA);
		doStuff(knownData.propB);
		//Etc...
	}
}

But of course to make sure TSC is not just doing weird stuff that's confusing Terser, I decided to make a minimum reproducible example in pure JS. Here is the most simple example I could force it to not filter the line out in:

javascript
function test(val) {
	const data = val.data;
	function subFunc() {
		const d = data;
		console.log(d.a, d.b);
	}
	return subFunc;
}

Terserized w/ compress: {unsafe: true}

javascript
function test(n){const t=n.data;return function(){const n=t;console.log(n.a,n.b)}}

But change some tiny thing like this and suddenly, it works:

javascript
function test(val) {
	const data = val.data;
	function subFunc() {
		const d = data;
		console.log(d.a);
	}
	return subFunc;
}

Terserized:

javascript
function test(n){const t=n.data;return function(){console.log(t.a)}}

I also tested with all of the other extra unsafe options enabled too just to check, and it still doesn't filter this out btw.