Typescript类型匹配对象,其valueOf最终返回一个字符串

时间:2019-01-24 22:37:36

标签: typescript typescript-typings

我正在过度设计与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()位于原型上而不是对象本身的定义有关。我不知道为什么会这样。

1 个答案:

答案 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()创建的循环。

希望这会有所帮助。