TypeScript Version: 2.2.1
Code
class Person {
firstName: string;
lastName: string;
get fullName?() {
return this.firstName + ' ' + this.lastName;
}
}
Expected behavior:
Since fullName
is optional the following should work:
const Me: Person = {
firstName: 'Foo',
lastName: 'Bar'
}
Actual behavior:
A syntax error occurs on this line get fullName?() {
I'm not sure if omitting the ability to optionalize getters was by design or not. If it was by design, I'd love to know the reasoning behind it.
A class is an implementation of a type. if you want to declare an optional property i suggest adding an interface Person
:
interface Person {
firstName: string;
lastName: string;
readonly fullName?;
}
Thanks! I'm aware that that's a possibility.
I suppose I just don't understand why the language would disallow marking getters as optional when _everything else_ on a class can be marked as optional. It seems inconsistent. Is there a good reason for this inconsistency? Forgive me if I misunderstand, but the "A class is an implementation of a type" reasoning seems more like a how-the-_compiler_-is-implemented reason as opposed to a how-the-_language_-should-work reason. I'm interested in the later.
Accessors (getters/setters) are just properties. you can declare methods and properties as option. but you can not have an implementation to an optional property or a method.
Maybe I misunderstand. You _can_ specify an implementation to an optional class method:
class Person {
getName?() {
return 'This is the name';
}
}
There are no errors with that.
@mhegazy Like bradenhs said, class methods can be made optional, as shown in this merged PR: https://github.com/Microsoft/TypeScript/pull/8625
class Bar {
h?() {
return 2;
}
}
As can be seen, it's an optional method that also has a body/implementation specified.
That's the same thing we'd like for class getters/setters, like so:
class Bar {
get h?() {
return 2;
}
}
However, this doesn't compile currently, which seems inconsistent when class methods work with it fine.
@mhegazy seems inconsistent to allow (bodied) optional methods but not getters. Thoughts?
If this suggestion is accepted would you guys take a PR for it? (I don't know much about the TypeScript code base but this doesn't _seem_ like it would be a complicated task).
@ahejlsberg I saw that you implemented the ability to optionalize class properties in https://github.com/Microsoft/TypeScript/pull/8625. Is there a specific reason the ability to optionalize getters was omitted from that PR?
Accepting PRs to allow this with similar semantics as optional methods.
I think I'll take a stab at this. It would allow for some better patterns in the state management library I'm creating for my CS498R class (nearly graduated!)
Finally had some time to go ahead and implement this. Take a look at the PR here #16344.
Any updates on this? Can we get the PR merged?
@jahtalab It's been a while and I need to update the PR. I'm taking a couple "hobby programming" days off from work this next month so I may get to it then.
To anyone who is skimming through this conversation and wonders why last comment was as much time ago as 29. Jan: the more up-to-date conversation (up to 26 days ago) is on https://github.com/Microsoft/TypeScript/pull/16344
Interesting history behind this PR, btw :). Is this situation common?
Related to this issue, I wish to propose that setters allow optional arguments, as it seems inconsistent when compared to regular methods, e.g.
class C {
setX(n?: number) {} // Allowed.
set x(n?: number) {} // Not allowed: "A 'set' accessor cannot have an optional parameter."
}
The main problem being, you cannot allow passing undefined
or null
to such a setter.
@inad9300 see #2521
I'm not sure @inad9300 's question is actually about #2521. set x(n: number | undefined) { }
is valid and probably what they meant to specify. It's not just that setters can't have optional parameters, it's that setters must always have exactly one parameter (and its type must be the same as the getter, if specified). They also can't have two or ten parameters.
If you think about it for a second, though, it makes sense. The setter is called when an assignment operator is encountered, but a syntactically valid assignment always has exactly one l-value and one r-value, even if that r-value is undefined
. Thus, you can't ever call the setter function with anything other than exactly one argument, so it doesn't make sense to support declaring it with anything other than exactly one parameter.
any update?
I am tired of writing entity.id()
, i want entity.id
but then creating the entity without id is not possible
const entity = new Entity({name:'xyz}:Entity) // property id is missing
This should be allowed, which is only possible when id
can be optional property.
You don't need this to solve your specific use case. You could just declare your class with constructor(other: {name: string})
or constructor(other: Partial<Entity>)
or even constructor(other: Omit<Entity, "id">)
.
@RyanCavanaugh is there any update on this issue? it has literally been years now.
I didn't even notice when I made my previous comments that there are actually at least two issues in this ticket. One, can I declare a class whose getters are optional? (I still don't understand the actual use case here -- if you don't new
a class instance from an existing implementation, instanceof
doesn't work.) Two, why can't I make the argument to a setter optional? (Setters are only called when doing assignments, and there's always exactly one r-value, even if it's explicit null
or undefined
.)
@xtianus79 are you trying to get an update on "issue one"? If so, the linked PR #16344 has some back-and-forth but looks like it needs some extra discussion before it gets resolved.
@thw0rted use case could be to not have to use them in call signatures eg when using classes as interfaces
I hadn't thought about the "classes as interfaces" thing because I don't actually do that myself. Are there particular times when it makes more sense than just writing an explicit interface definition? If you're making methods (and getters) optional entirely so that you can use the class as an interface, wouldn't it mean that reads always need conditional access even though you know that, for actual instances of the class, they're always defined?
Oof. I just ran into this myself. Funny thing is the IDE (PhpStorm) doesn't see get foo?()
as a problem 馃樀
For now I did get foo(): string|null
which compiles but doesn't seem to be recognized by the IDE. Oh well.
Most helpful comment
@mhegazy Like bradenhs said, class methods can be made optional, as shown in this merged PR: https://github.com/Microsoft/TypeScript/pull/8625
As can be seen, it's an optional method that also has a body/implementation specified.
That's the same thing we'd like for class getters/setters, like so:
However, this doesn't compile currently, which seems inconsistent when class methods work with it fine.