Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Different external and internal names for props #10

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

JosephSilber
Copy link

View fully rendered RFC


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

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

@posva
Copy link
Member

posva commented Feb 1, 2019

Also at vuejs/vue#7943

@LinusBorg
Copy link
Member

I like the idea, nice work!

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

@laander
Copy link

laander commented Feb 3, 2019

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

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

@jonaskuske
Copy link

jonaskuske commented Feb 3, 2019

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.

@darrenjennings
Copy link

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.

@chriscalo

This comment has been minimized.

@garygreen

This comment has been minimized.

@posva posva changed the title Prop aliases Different external and internal names for props Feb 8, 2019
@gruhn
Copy link

gruhn commented Feb 8, 2019

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.

@znck
Copy link
Member

znck commented Feb 19, 2019

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

@thedamon
Copy link

thedamon commented Jan 6, 2020

@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) }
  }
}

@KorHsien
Copy link

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.

@CyberAP
Copy link
Contributor

CyberAP commented Sep 15, 2020

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.

@yogeshgalav
Copy link

#513
It might resolve this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.