我正在过度设计与string
匹配的类型,或者对它的valueOf()
进行递归求值的对象最终返回string
的对象。
type Stringable = string | StringableObject;
interface StringableObject {
valueOf(): Stringable;
}
let x: Stringable;
// should 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
};
Object.prototype.valueOf()
在未被覆盖的情况下会返回object
,而不是string
,所以我很困惑为什么最后的情况会编译,而我需要更改使其不被编译
我怀疑我需要创建一个使用infer
关键字的泛型类型,但是我仍在尝试如何正确使用infer
。
奇怪的是,如果我将valueOf
更改为foo
,它会达到我的期望。
type Stringable = string | StringableObject;
interface StringableObject {
foo(): Stringable;
}
// do not compile
x = {};
x = {
foo() { return 1; }
};
x = {
foo() {
return {
foo() { return 1; }
};
}
};
我认为它要么与valueOf()
本身的性质有关,要么与valueOf()
位于原型上而不是对象本身的定义有关。我不知道为什么会这样。
答案 0 :(得分:1)
这里存在一些误解,因此我将尝试分别解决每个误解,希望这将有助于解释为什么您的代码未产生预期的结果。
Object.prototype.valueOf()
在没有被覆盖的情况下会返回一个对象,而不是字符串,因此我很困惑为什么最后的情况会编译,而我需要更改使其不被编译。
valueOf()
返回调用它的对象的原始值。 JavaScript将字符串文字(例如'foo'
)视为原语,但由于原语没有属性,因此JavaScript将原语强制转换为Objects(实际上,它将尽可能强制转换任何类型以使操作有效) )以允许在原语为无效类型的情况下进行操作。查看this StackOverflow post,了解有关对象强制的更多信息。这对您来说意味着valueOf()
不一定会返回一个Object,而是会调用它的任何类型的原始值:
> "foo".valueOf()
'foo'
> let x;
> x = {}; x.valueOf()
{}
> x = 10; x.valueOf()
10
我正在过度设计一个与字符串匹配的类型,或者对它的对象进行递归求值时其valueOf()最终返回一个字符串。
StringableObject
接口未描述其valueOf()
方法最终将返回字符串的类型。它确实描述了一个类型,该类型的valueOf()
方法将返回带有valueOf()
方法的类型,该类型将返回带有valueOf()
方法的类型,等等,这是无穷无尽的。您的第一个代码块中的这一行:
x = {};
x
被分配给一个对象常量,该对象常量可以强制转换为一个Object
方法,该对象的valueOf()
方法返回一个新的原语,该原语也具有一个valueOf()
方法,该方法产生一个可以强制为Object
等基本元素,等等。
在第二个代码块中,将valueOf()
方法更改为foo()
,该方法作为全局Object
类型的方法不存在,因此不能满足无限的{{1} }由您的原始valueOf()
创建的循环。
希望这会有所帮助。