Issue 1:
Bug

Input Code

Here is link to babel playground

class MyMap extends Map {
constructor() {
super();
}
test() {
return "Hallo world";
}
}
var myMap = new MyMap();
console.log(myMap instanceof MyMap);
console.log(myMap.test());

Babel Configuration (.babelrc, package.json, cli command)

{
"presets": [
"env"
]
}

Expected Behavior

Should output in console:

true

"Hallo world"

Current Behavior

If I run it in Chrome v61 directly - works fine, but if I precompile it with babel then the following error logged:

Uncaught TypeError: Constructor Map requires 'new'
at MyMap.Map (<anonymous>)
at new MyMap (<anonymous>:17:99)
at <anonymous>:30:13

Possible Solution

There is a way to identify if the function is class by executing ".arguments" or ".caller". For regular functions it will return a value or undefined. But for classes (custom or system, like Map or Set) it will throw error 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them - maybe this can be used to solve this

Context

Cannot extend Map class

Your Environment

software
version(s)

Babel
6.26.0 latest available online at 10/9/2017

node
n/a

npm
n/a

Operating System
Win7 x64

Issue 2:
Current Babel transform, when it comes to call the parent

function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
}

It's a way too poor implementation.

If we take the current basic ES6 compat syntax:

class List extends Array {}

We'll realize babel does a bad job.

var l = new List();
l instanceof List; // false

The reason is simple: Babel replace the returns and exit, without caring about userland expectations.

This is how above basic extend should desugar:

function List() {
return Object.setPrototypeOf(
Array.apply(this, arguments),
List.prototype
);
}

It's a very ad-hoc case for the initial example that currently fails, but it's good enough to understand that inheriting the prototype is the least of the problem.

Indeed, we have 3 ways to do that within a transpiled code:

// losing the initial prototype
// for polyfilled ES5+ or lower
List.prototype = Object.create(
Array.prototype,
{constructor: {
configurable: true,
writable: true,
value: List.prototype
}}
);

// using a cleaner way
// for ES5+ compliant targets
Object.setPrototypeOf(
List.prototype,
Array.prototype
);

// using a cleaner way
// that works well with
// partially polyfilled .setPrototypeOf
List.prototype = Object.setPrototypeOf(
List.prototype,
Array.prototype
);

Solved the inheritance bit, considering Babel also set the prototype of each constructor,

we need to address cases where a super call might "upgrade" the current context, like it is for HTMLELement or exotic native objects.

// native ES6 static example
class List extends Array {
constructor(a, b, c) {
super(a, b);
this.push(c);
}
}

Above case should desugar to something like the follwoing:

function List(a, b, c) {
// the super bit
var self = Object.setPrototypeOf(
Array.call(this, a, b),
List.prototype
);
// the rest with swapped context
self.push(c);
// at the end
return self;
}

which is also ad-hoc example code for the previous example.

Considering a transpiler will get the arguments part easily right, this is how previous case could be generically transpiled for arguments used in both constructors:

// to make it as generic as possible
function Child() {

// the super call bit desugar to ...
var
instance = Object.getPrototypeOf(Child)
.apply(this, arguments),
type = instance ? typeof instance : '',
// if Parent overwrote its default return
self = (type === 'object' || type === 'function') ?
// upgrade the instance to reflect Child constructor
Object.setPrototypeOf(instance, Child.prototype) :
// otherwise use the current context as is
this
;

// at this point, the rest of the constructor
// should use `self` instead of `this`
self.push(c);

// and return `self` reference at the end
return self;
}

The last problem is that modern syntax would use Reflect to create any sort of object, instead of old, ES3 friendly, .call or .apply way.

Following a past, present, and even future proof approach:

var
reConstruct = typeof Reflect === 'object' ?
Reflect.construct :
function (Parent, args, Child) {
return Parent.apply(this, args);
}
;

function Child() {

// the super call bit
var
instance = reConstruct.call(
this,
Object.getPrototypeOf(Child),
arguments,
Child
),
type = instance ? typeof instance : '',
self = (type === 'object' || type === 'function') ?
Object.setPrototypeOf(instance, Child.prototype) :
this
;

// the rest of the constructor body
self.push(c);

// at the end or instead of empty returns
return self;
}

Above solution would work with userland, exotic, or DOM constructors, and in both native and transpiled engines.