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?
null
, I'd have to add some extra checks in one of my libraries to handle that situation. But no, my question is more about general curiosity. – Cementumnull
IIRC). But as soon as you start manipulating a primitive it is converted to its associated object type. E.g.,foo = 'foo'
is a primitive string--but you can call methods on it,foo.toUpperCase()
, because of the conversion. geeksforgeeks.org/… may help. – Gerardgerardo