Vue-next: computed implement toString

Created on 29 May 2020  路  6Comments  路  Source: vuejs/vue-next

What problem does this feature solve?

const person = reactive({ firstName: "John", lastName: "Doe" });  // reactive field
const fullName = computed(() => `${person.firstName} ${person.lastName}`); // effect


console.log(`You are logged as: ${fullName.value}`); // Yo

What does the proposed API look like?

console.log(`You are logged as: ${fullName}`); // Yo

maybe code change

  computed = {
    __v_isRef: true,
    // expose effect so computed can be stopped
    effect: runner,
    get value() {
      if (dirty) {
        value = runner()
        dirty = false
      }
      track(computed, TrackOpTypes.GET, 'value')
      return value
    },
    set value(newValue: T) {
      setter(newValue)
    },
    toString() {
      return this.value // THIS
    },
  } as any

Most helpful comment

@marcusball, toString() is not available on all types, try type 10.toString() into console.

Proper way is to use String.

toString() {
  return String(value)
}

But is worth to check what does transpiled string interpolation. Maybe it does it automatically.


I don't think it is needed at all. Calling .value is more consistent with rest of the code. It would be really crazy to have half stuff with .value and half without it. (even when reactive object already does something similar) and template-compiler transpiles it in view.

PS: The value is there because you need to tell to the wrapper, you want to compute the value. (otherwise there is no way to detect when it should run)

All 6 comments

I'm not sure if this is a dumb suggestion, but would it be better if the return was return this.value.toString()? That seems like it might help support more types and nested objects.

@marcusball, toString() is not available on all types, try type 10.toString() into console.

Proper way is to use String.

toString() {
  return String(value)
}

But is worth to check what does transpiled string interpolation. Maybe it does it automatically.


I don't think it is needed at all. Calling .value is more consistent with rest of the code. It would be really crazy to have half stuff with .value and half without it. (even when reactive object already does something similar) and template-compiler transpiles it in view.

PS: The value is there because you need to tell to the wrapper, you want to compute the value. (otherwise there is no way to detect when it should run)

@sionzeecz

try type 10.toString() into console.

image

@jacekkarczmarczyk

uh, I see, the first dot is used as decimal point and the second one for a function call.
More understandable for me looks String(10) than 10..toString().

Anyway thank you for a lesson :)

x.toString() throws if x is null or undefined.

String(x) handle those cases, but, in some cases, it can be misleading or opaque. Here are some examples:

  • String({}) === '[object Object]'
  • String([]) === ''
  • String([2]) === String(2)
  • String('2') === String(2)

Vue already has a good stringifier, that fallbacks to JSON.stringify and handles Map and Set, used for interpolations (e.g. {{ x }}).

If Vue implements this feature, it should reuse that stringifier IMHO.

This, while convenient, is very likely to lead users to get used to code like 'some string' + someRef - not just in logging and debugging, but also in actual code. Without type information and naming conventions, this can make the code more difficult to understand (is this a ref or an actual string?). On the other hand, magic toString is inherently incompatible with type checking and also makes static analysis more difficult.

If you really want it, you can easily wrap computed to attach toString to the ref yourself.

Was this page helpful?
0 / 5 - 0 ratings