But I wouldn't trust this trick for type-safety checking
constuser={name:'John',[Symbol.toStringTag]:'User',};deleteuser.name;if (user[Symbol.toStringTag]==='User'){// cool, `user` is a User, it must have the `name` property!user.name.length;// fails}
whereas in TypeScript, any operation changing the shape of an object outside of its type is prevented
typeUser={name:string}constuser={name:'john'}deleteuser.name;// Error: The operand of a 'delete' operator must be optional.(TS2790)
typeUser={name:string}constuser={name:'john'}Object.defineProperty(user,"name",{value:undefined});alert(user.name.length);// Cannot read property 'length' of undefined (in JavaScript after transpilation)
This compiles just fine in TypeScript and even gives an error in the playground when run.
Grew up taking things apart. Acquired natural predisposition for problem solving to avoid punishment. Now, adult me breaks things and solves all kinds of fun problems.
Location
New York City, NY
Education
Winthrop University
Work
Principal Software Engineer, though more accurately; aggressive, professional Googler
It's important not to forget that, at the end of the day, TypeScript isn't anything more than code sugar, pre-compilation. Post-compilation (and subsequent runtime), it's all regular ole' JavaScript. Nothing more. Nothing less. Enforcing "Type" safety in any kind of "strict" manner, will always, always, always only go so far. ECMAScript Primitives are the only datums which, natively, guarantee preserving "Type"(Undefined, Null, String, Boolean, Number, and Symbol). All remaining ECMAScript types/values fall under "Object Type" classifications/sub-classes. Why is any of this important? Objects, (be it a "POJO", function, constructor, exotic, emoji, whatever), by their very nature in JavaScript land are not ever going to be "secure", ESPECIALLY in terms of structural exposition/composition (i.e. "interface" or "shape"). However, we CAN secure "Object Type" checks and guards that remain true at runtime by placing the intended "Type" enforcements around the instance itself.
Nice, I didn't know about this!
But I wouldn't trust this trick for type-safety checking
whereas in TypeScript, any operation changing the shape of an object outside of its type is prevented
I agree, however there's other ways to prevent this like freezing or using Proxies.
This compiles just fine in TypeScript and even gives an error in the playground when run.
Sure, but come on, that's just deliberately trying to deceive TypeScript at this point ^^
It's important not to forget that, at the end of the day, TypeScript isn't anything more than code sugar, pre-compilation. Post-compilation (and subsequent runtime), it's all regular ole' JavaScript. Nothing more. Nothing less. Enforcing "Type" safety in any kind of "strict" manner, will always, always, always only go so far. ECMAScript Primitives are the only datums which, natively, guarantee preserving "Type"(Undefined, Null, String, Boolean, Number, and Symbol). All remaining ECMAScript types/values fall under "Object Type" classifications/sub-classes. Why is any of this important? Objects, (be it a "POJO", function, constructor, exotic, emoji, whatever), by their very nature in JavaScript land are not ever going to be "secure", ESPECIALLY in terms of structural exposition/composition (i.e. "interface" or "shape"). However, we CAN secure "Object Type" checks and guards that remain true at runtime by placing the intended "Type" enforcements around the instance itself.
Totally agreed! Thank you!