Tuesday, 7 December 2021

Can a constructor ever return a primitive?

I'm asking this question because I've noticed that TypeScript allows declaring constructors that return primitive types, e.g.:

type Constructor1 = new () => string; // Primitive string

as opposed to

type Constructor2 = new () => String; // String object

This made me wonder if JavaScript actually permits creating a function that returns a primitive value when invoked with new semantics, i.e. a value that passes the primitiveness test:

function isPrimitive(value) {
    return value !== Object(value);
}

Needless to say, I could not find any example of a constructor invocation that produces a primitive value, so I imagine this must be just another weirdness of the TypeScript type model. Or does a primitive constructor really exist?


For reference, this is what I have tried out.

Predefined constructors

The predefined constructors Number, Boolean, String, etc. all produce an object when invoked with new, although they return a primitive value when called as regular functions. i.e.

isPrimitive(new Number()) // false

isPrimitive(Number())     // true
function isPrimitive(value) {
    return value !== Object(value);
}

console.log(isPrimitive(new Number()));
console.log(isPrimitive(Number()));

return in constructor

A return statement overrides the instance of this in the constructor, but only if the return value is an object:

const OBJECT = { foo: "bar" };
const PRIMITIVE = "baz";

function TheObject() {
    return OBJECT;
}

function ThePrimitive() {
    return PRIMITIVE;
}

console.log(isPrimitive(new TheObject()));    // prints false
console.log(isPrimitive(new ThePrimitive())); // prints false
function isPrimitive(value) {
    return value !== Object(value);
}

const OBJECT = { foo: "bar" };
const PRIMITIVE = "baz";

function TheObject() {
    return OBJECT;
}

function ThePrimitive() {
    return PRIMITIVE;
}

console.log(isPrimitive(new TheObject()));    // prints false
console.log(isPrimitive(new ThePrimitive())); // prints false

construct trap

A proxy can provide a construct trap to handle invocations to a function with new syntax. Whatever object the trap returns will be also returned by the constructor invocation. But, if a trap returns a primitive value other than undefined, a TypeError occurs.

const FooConstructor = new Proxy(
    class { },
    { construct: () => 'foo' }
);

new FooConstructor(); // throws TypeError: proxy [[Construct]] must return an object
function isPrimitive(value) {
    return value !== Object(value);
}

const FooConstructor = new Proxy(
    class { },
    { construct: () => 'foo' }
);

new FooConstructor();

More ideas?



from Can a constructor ever return a primitive?

No comments:

Post a Comment