In the process of overengineering a type that can match either a string
or an object whose valueOf()
function, when evaluated recursively, ultimately returns a string
.
type Stringable = string | StringableObject;
interface StringableObject {
valueOf(): Stringable;
}
let x: Stringable;
// expected to work:
x = 'foo';
x = {
valueOf() { return 'foo'; }
};
x = {
valueOf() {
return {
valueOf() { return 'foo'; }
};
}
};
// should not work but do:
x = {}; // valueOf() returns an object -- a reference to x, itself
x = {
valueOf() { return 1; } // valueOf() returns a number
};
Normally, Object.prototype.valueOf()
will return an object
if not explicitly overridden. So I'm puzzled as to why the last cases compile and what changes are needed to prevent them from compiling.
I have a hunch that creating a generic type utilizing the infer
keyword might be the solution, but mastering how to use infer
effectively is still a challenge for me.
Interestingly, renaming valueOf
to foo
produces the expected results.
type Stringable = string | StringableObject;
interface StringableObject {
foo(): Stringable;
}
// these should not compile
x = {};
x = {
foo() { return 1; }
};
x = {
foo() {
return {
foo() { return 1; }
};
}
};
I suspect the issue might lie with the behavior of valueOf()
itself or perhaps because valueOf()
resides in the prototype rather than being specifically defined on the object. However, I am unsure why this distinction matters.