So, if you want to slice off an object and name it just use ES6 classes.

class NameMe {
constructor (obj) {
for (var prop in obj) this[prop] = obj[prop];
}
}

This literally just spits out a named object with an identical structure to the object it's being created with.

If you want to make all keys visible and guarantee no exceptions are thrown when a key isn't set, just define default values.

class NameMe {
string = '';
number = 0;
bool = false;
array = [];
object = {};

constructor (obj) {
for (var prop in obj) this[prop] = obj[prop];
}
}

You could always gasp initialize everything to null if you're concerned about the defaults screwing up application logic. That's how static type systems address initialization by default anyway.

Want to enforce specific types? Add setter methods that include validation checks. Do I need to continue?

None of these characteristics are difficult to define in Javascript. Structuring data in a manner that's easy to reason about is no more difficult in Javascript than it is in any typed language. Even before the introduction of classes you could achieve the same using prototypes.

If the code you've encountered was difficult to reason about, it's because the devs who wrote it suck at writing code that's easy to reason about. Self-documenting code is a naming problem not a type theory problem.

Any code base, whether static or dynamic should contain an extensive collection of mock data and unit tests to verify common cases and check for breaking edge cases. Unless the project is a one-off fire-and-forget implementation. In which case; who cares, maintenance is somebody else's problem (I'm not stating this is a good ides, just what usually happens in practice).

----

Bonus: How about a couple of cases that 'literally can't even' be done in statically typed OOP languages.

Extending existing objects:

Sure, you can use object inheritance but that requires explicitly defining a class that represents the new structure. Except that now creates a deeply coupled relationship between the child and parent classes. Which will inevitably become a maintenance issue if the business logic ever changes. Say hello to technical debt.

Proof: Why do all of the collection classes in Java inherit from vector?

You can accomplish the same in JS in any object (class based or not) using .extend() (provided by most 3rd party frameworks). Which essentially does a deep copy of all the object properties. No deep coupling between objects, no technical debt incurred.

Multiple Inheritance:

I'm surprised nobody in the OOP community talks about this anymore.

Since OOP relationships between objects only point to the external interfaces (ie class definition) rather than reference the underlying data, there needs to be a system to represent those relationships.

Multiple inheritance was cast off as not technically feasible due to the possibility of users creating circular references. Ala 'the diamond problem.'

The solution. Branch everything off of a central 'god object' and represent all relationships between classes as a directed acyclic graph.

This is an artificial constraint that only applies to OOP. That not only makes it unnecessarily painful to reason about the structure of class definitions, but it makes it impossible to pass data to adjacent leaves in the DAG without some form of external global state (ie the singleton pattern).

In JS it's very easy to use multiple inheritance. Just create an object and add data from as many other objects as you want using .bind(). Done with an object but still need to maintain it's state? return a new function that maintains a reference to it's enclosing function. Ie use it as a closure.

Stop for a second to consider. The .bind() method, which is crucial to adding functional-like aspects to an imperative programming language, is physically not possible in OOP. The closest equivalent is to pass in ref/out params as arguments into the constructor (ie creating more deep links to external classes).