rfcs icon indicating copy to clipboard operation
rfcs copied to clipboard

Different external and internal names for props

Open JosephSilber opened this issue 6 years ago • 13 comments
trafficstars

View fully rendered RFC


Allow aliasing props, to have different external and internal names (some languages call these "argument labels"):

props: {
    externalName: {
        as: 'internalName'
    }
}

JosephSilber avatar Feb 01 '19 16:02 JosephSilber

Also at https://github.com/vuejs/vue/issues/7943

posva avatar Feb 01 '19 17:02 posva

I like the idea, nice work!

One thing I'm concerned about (but not qualified to answer) is how this complicates typings for Typescript.

LinusBorg avatar Feb 03 '19 19:02 LinusBorg

Nice. I think alias get's my vote, reads better without further explanation:

props: {
    ageOfPerson: {
        type: Number,
        alias: 'age'
    }
}

laander avatar Feb 03 '19 21:02 laander

Hmm, if we call it alias it'd have to work like an actual alias in my opinion, meaning both names would work when passing props – the same way aliases in Vue Router don't replace the path of a route but, well, alias it.

So for a component Greet.vue with

{
  props: {
    fullName: {
      type: String,
      alias: 'name',
  }
}

these would have to result in identical output: <Greet name="Eddy Example" /> <Greet full-name="Eddy Example" />

If we don't want an alias but "to have different external and internal names" then as is more accurate.


TL;DR: If it's an actual alias and both names are valid when passing props, call it alias. Otherwise as (or maybe something completely else) is more accurate.

jonaskuske avatar Feb 03 '19 21:02 jonaskuske

this is great! I like the initial idea "as", since it is intuitive coming from js module imports

import { externalName as name } from 'someModule'

Agree with @jonaskuske that if it's "alias", then it looks like the prop can be used by either name, which can be confusing since props are usually a form of documentation.

darrenjennings avatar Feb 05 '19 03:02 darrenjennings

Might it be able to accept multiple aliases by providing an array?

{
  props: {
    fullName: {
      type: String,
      alias: ['name', 'fullname'],
  }
}

chriscalo avatar Feb 08 '19 16:02 chriscalo

Might it be able to accept multiple aliases by providing an array

I would say that's overcomplicating it, if you want to provide an extra alias, you can do that in your own data method.

garygreen avatar Feb 08 '19 16:02 garygreen

For real aliases you can already utilise computed properties

props: ['external'],

computed: {
  internal () {
    return this.external
  }
}

Sure this is a little bit verbose but it elegantly arises from Vues natural capabilities.

EDIT 1: ok sorry, I didn't read the full RFC.

EDIT 2: Hmm... I still think I have a point though. You just really really want to keep using the external prop name even when you plug a computed property in-between. I think that's a rather trivial use case though.

gruhn avatar Feb 08 '19 20:02 gruhn

There is an API available for provide/inject feature to have different local name, I think we should use similar API for props.

props: {
  localName: {
    from: ‘externalName’
  }
}

https://vuejs.org/v2/api/#provide-inject

znck avatar Feb 19 '19 06:02 znck

@JosephSilber I really like this. A lot. I think you could expand the RFC text to mention that when/if it can combined with computed instead of data, it also essentially enables the ability to do prop coercion and set prop defaults based on other props:

Stateful prop defaults

{
  props: {
   link: String,
   linkType: {
     type: String,
     as: 'rawLinkType'
   }
  }
  computed: {
    linkType(){ return this.rawLinkType || this.link.startsWith('mailto:') ? 'email' : 'default' }
  }
}

Prop coercion

{
  props: {
   title: {
     type: String,
     as: 'rawTitle'
   }
  }
  computed: {
    title(){ return titleCase(this.title) }
  }
}

thedamon avatar Jan 06 '20 16:01 thedamon

I think the examples list in the Motivation section of the RFC (as well as some use cases commented) are not good arguments for this proposal.

  1. This example expresses its intent quite accurately, the prop name indicates that it's the initial value, which is different from the internal mutable value. I think making this distinction is preferable.
props: ['initialCounter'],
data() {
  return {
    counter: this.initialCounter
  }
}
  1. This example is a bit representative for a lot of arguments around the previously commented use cases of props coercion, sanitization or preprocessing in general.
props: ['size'],
computed: {
  normalizedSize() {
    return this.size.trim().toLowerCase()
  }
}

With the introduction of Composition API, those use cases could be handled elegantly:

props: ['size'],
setup(props) {
  const size = computed(() => {
    return props.size.trim().toLowerCase()
  })

  return {
    size
  }
}

That being said, I'm not entirely against this. The Swift example in the RFC regarding argument labels is what in the similar vein with this proposal. Take that example into the context of Vue:

props: {
  person: String,
  from: {
    as: 'hometown',
    type: String
  }
}

And take the example of the new <teleport> component (though it's not implemented with normal component options). Its target prop name is to, but it's not ideal to refer it internally as to. For the sole purpose of renaming (or aliasing), we could do it in setup function:

props: {
  to: {
    type: [String, Element]
  }
},
setup(props) {
  const target = toRef(props, 'to')

  // setting up

  return {
    target
  }
}

But it's not as expressive and cohesive as following IMO:

props: {
  to: {
    as: 'target',
    type: [String, Element]
  }
},
setup(props) {
  // setting up

  return {
    //
  }
}

So, in summary:

  1. IMHO it's a bit of a detour to use this feature to solve the problems of props preprocessing of sort.
  2. This proposal can be useful for providing the feature of argument labels.

KorHsien avatar Apr 19 '20 15:04 KorHsien

Just to clarify: it's not possible to solve that with Composition, you'll get an error for using a property with the same name as in props.


I think this change complicates things a lot more than it actually helps a developer. TypeScript support would be poor for this and probably require manually typing your props. It would also be unclear what value is being used in context without looking at props declaration first. Additionally since you can't mutate props but probably are going to use that value as an initial value in data that alone introduces confusion: component takes a prop foo then internally mutates foo context value. It's much more clear when we have foo as a prop and currentFoo as an internal state. Lastly, it can be mitigated by wrapping internal state into an object, which I think has a well balanced developer experience.

CyberAP avatar Sep 15 '20 05:09 CyberAP

https://github.com/vuejs/rfcs/discussions/513 It might resolve this issue.

yogeshgalav avatar Apr 29 '24 19:04 yogeshgalav