$ mol_strict: How about me [object Object] this undefined NaN of yours‼

Hello, my name is Dmitry Karlovsky and I ... do not forgive mistakes. As soon as I see it, I immediately throw something extremely heavy. And how hard the work of a JS programmer is ...







class Foo extends Object {}
const foo = new Foo

`, ${ foo }!`
// " [object Object]!"

`     ${ foo / 1000 }  .`
// "     NaN  ."

`  "${ 'foo'[4] }" - .`
// "  "undefined" - ."

`  ${ foo.length - 1 }     .`
// "  NaN     ."
      
      





There are several ways to ease his suffering.







  1. Cover yourself with a typescript. But in runtime, the feet still remain bare, and someone always steps on them.
  2. To impose checks. But you hesitate a little and the runtime rake immediately hits the head.
  3. Fix JS. Don't even hope.
  4. Fix JS runtime. Well, let's think ..


JS dynamic typing problems arise for 2 main reasons:







  • Automatic (and sometimes inappropriate) typecasting when a value of one type is used in a context intended for another.
  • Return undefined as the value of un-declared fields.


. JS , . . , :







Object.prototype[ Symbol.toPrimitive ] = function() {
    throw new TypeError( `Field Symbol(Symbol.toPrimitive) is not defined` )
}
      
      





, , Symbol.toPrimitive



.







, . - … - ! … , .







- , . JS — . , :







export let $mol_strict_object = new Proxy( {}, {

    get( obj: object, field: PropertyKey, proxy: object ) {
        const name = JSON.stringify( String( field ) )
        throw new TypeError( `Field ${ name } is not defined` )
    },

})
      
      





, prototype



Object



, , . Object.prototype



null



. Object



:













:







for( const name of Reflect.ownKeys( $ ) ) {
    // ...
}
      
      





, :







const func = Reflect.getOwnPropertyDescriptor( globalThis, name )!.value
if( typeof func !== 'function' ) continue
if(!( 'prototype' in func )) continue
      
      





, globalThis[name]



, .







, Object



:







const proto = func.prototype
if( Reflect.getPrototypeOf( proto ) !== Object.prototype ) continue
      
      





, , Object.prototype



:







Reflect.setPrototypeOf( proto, $mol_strict_object )
      
      





, , . , .







, , Object, , EventTarget, .







CSSStyleDeclaration



: ( , ), , , 89 style



dom-:







( <div style={{ color: 'red' }} /> ).outerHTML // <div></div>
      
      





.







… :







class Foo {}
      
      





. :







class Foo extends Object {}
      
      





… . Object



:







globalThis.Object = function $mol_strict_object( this: object, arg: any ) {
    let res = Object_orig.call( this, arg )
    return this instanceof $mol_strict_object ? this : res
}

Reflect.setPrototypeOf( Object, Reflect.getPrototypeOf({}) )
Reflect.setPrototypeOf( Object.prototype, $mol_strict_object )
      
      





, Object



, .







, ...







class Foo extends Object {}
const foo = new Foo

`, ${ foo }!`
// TypeError: Field "Symbol(Symbol.toPrimitive)" is not defined

`     ${ foo / 1000 }  .`
// TypeError: Field "Symbol(Symbol.toPrimitive)" is not defined

`  "${ 'foo'[4] }" - .`
// TypeError: Field "4" is not defined

`  ${ foo.length - 1 }     .`
// TypeError: Field "length" is not defined
      
      





, , :







, - . — .







, : JavaScript ?.







: $mol_strict.







NPM - :







import "mol_strict"
      
      





:







require("mol_strict")
      
      





$mol : $mol: Usage from NPM ecosystem.







JS , :









, _jinnin , JS, UX .








All Articles