TypeScript: preset class properties to undefined
TypeScript Version: 2.1.1
Code
class PartialPolicySearchIten {
public displayValue: string;
public oriNumber: string;
public parentName: string;
public sysNumber: string;
public systemCode: number;
public systemName: string;
}
Expected behavior:
class PartialPolicySearchIten {
constructor() {
this.displayValue = undefined;
this.oriNumber = undefined;
this.parentName = undefined;
this.sysNumber = undefined;
this.systemCode = undefined;
this. systemName = undefined;
}
}
Actual behavior: class PartialPolicySearchIten { }
The problem comes when using Reflection it can’t find the properties. I would expected that the properties exists as i’m redefining them. Otherwise their very little point is declaring properties of a class.
About this issue
- Original URL
- State: closed
- Created 8 years ago
- Reactions: 15
- Comments: 31 (12 by maintainers)
For type-only information something like this could work:
(Public) class fields are enabled by default in Chrome 72 with the initializer semantics outlined above. This part of the spec is extremely unlikely to change. Current topics of debate are just how private fields should work AFAICT.
Can we please revisit and get a decision here? While the Babel transform is not officially supported, they would want to wait for a decision by the TypeScript team before implementing any fixes: https://github.com/babel/babel/issues/9105
The major arguments for keeping the current semantics to me are:
In favor of switching:
Any input would be much appreciated ☺️❤️
@IgorSzymanski this continual moving of the goalposts isn’t indicative of a good-faith conversation. If you don’t think it’s important to you, that’s fine, but no one is required to justify spec compliance as a valid goal
Any news on this? This kind of behavior is as important as common and standard. Would be great to fix it.
While this is the original/current behavior, the current ES proposal seems to actually imply that a property will indeed be defined & set to
undefinedeven without an initializer.https://tc39.github.io/proposal-class-public-fields/#initialize-public-static-fields
You need to explicitly initialise them as undefined to have the effect you want.
Input
Output
Therefore I think that this is not an issue but is intended behaviour.
Not yet, but we should probably change that.
Could I propose that only fields whose types include
undefinedbe initialized as such? It seems to me that initial example, where the fields were just removed, ought to be disallowed – if the value is non-optional but also never set in a constructor, then that should just be a type error.So this should be fine:
and this should be an error:
This is now the behavior under
--useDefineForClassFieldsThen initialise your properties explicitly. This is a breaking change, it breaks the logic behind explicit property initialisation and, once again, I do not see any use case where it should matter. In OOP, you shouldn’t really ask for properties of a class instance, because it breaks its encapsulation. In FP, you wouldn’t even use a class for this, and therefore you would have to initialise the property on your own. This change is nothing but an attempt to encourage a bad programming style.
I also do not see, why you would want to run a class instance against
Object.assignor object spread. Mind to elaborate?Give me a valid example of why the lack of implicit property initialisation in a class instance is an issue.
What is the use case for this one?
undefinedis the spiritual equivalent of the lack of a property, thus:If you want to do some dirty, 5-minute life hacks with iterating over an object properties (and I can smell from a mile, that it’s exactly what you’re trying to do), then
nullis for that to represent an existing property with en empty (NULLABLE) value. Even if JS/TS can produce and allows the existence of an object with a property initialised withundefinedvalue, it should be treated as if it wasn’t there in the first place.You’re partly correct, but there are ways that people with
strictNullChecksbut notstrictorstrictPropertyInitializationcan be broken by this, precisely it’s breaking in terms of compiler output, not only in terms of type-checking. If you have a way that a property is known to be initialized outside the constructor (e.g. component arguments, which may be checked via debug assertions or the like), the behavior can change with this. We saw these breaking changes in practice across many applications when we changed to using TS only for type checking and Babel (which is spec compliant) for actual compilation in Ember apps and addons.That said, deferring it to
strictPropertyInitializationorstrictdoesn’t seem unreasonable, since it’s impossible for this not to be a breaking change in some way. (It should, however, be code-mod-able given a satisfactory design.)Looks like there’s already https://github.com/microsoft/TypeScript/issues/39311.
Separate issue please. Thanks!
Anything using object spread or
Object.assignwill care about it being a present, own property, even if set toundefined.undefinedis not simply “not defined”, in JS, there exists “absent”, “present but set to undefined”, and “present but set to non-undefined”.@ljharb I ask again for the use case. Also, if you do not initialise and optional property, why do you expect it to be initialised with undefined? If you do not initialise an optional property, the expected behaviour is it’s not there, uninitialised shouldn’t be initialised, and that’s exactly what happens.
Also, the OP example is horrible.
If you define a property as non-optional
number, it should be nothing else, but anumber. No part of the code says it can beundefined.@kutomer I think what @nicolo-ribaudo wanted to express is that the
declarekeyword could be used as new syntax, i.e. it does not work yet and would be a breaking change to TypeScript. 🙂@nicolo-ribaudo not sure how it’s possible, tried it on ts playground and got
declare' modifier cannot appear on a class element.