Conditional Spread is More Prone to Losing | undefined
#41418
declareletbool: boolean;constobj={
...bool&&{x: 'x'},
...bool&&{y: 'y'},};constx: string=obj.x;obj.y=undefined;- After we added conditional spreading behavior after the RC, we saw that it was more prone to being found.
declareletr: {[key: string]: number};letfromExpression={ ...bool&&{x: 3}};r={ ...fromExpression};// OkdeclareletfromAnnotation: {x?: number};r={ ...fromAnnotation};// Error: Type 'undefined' is not assignable to type 'number'.- Type from
x includes undefined in fromAnnotation. - The behavior we're seeing right now is what's in the RC.
- The behavior is not new - it existed, it was just harder to observe.
declareletz: {a: string}|{};constzz={ ...z}- Have there been any other issues filed on this in the past?
- First, it is strange that an optional property is not assignable to an index signature.
- It is unclear if it's actually
undefined or missing.
- These are "past sins" that we can't correct.
- Co-mingling
undefined means we can't do anything.
- Maybe one rule: allow
undefined to be written to an index signature. - We also just have a bug - you cannot have properties that don't have
undefined in their type. - Should we allow optional properties to be assigned to an index signature?
- General agreement - we had some sense of urgency because we thought it became MUCH more observable - but probably just only a little bit more observable.
constobj2={m: Math.random()>0.5 ? undefined: ""};constq: {m?: string}=obj2;consta: {[s: string]: string}=q;if("m"ina){a["m"].toUpperCase();}- With the optionality rule,
obj2 is not assignable to a, but q is assignable to a.
- Non-transitivity has always been the case ¯\_(ツ)_/¯
- Continue next week?
Backing out resolve Changes
#41497
- The assignability issue is really closer to a bug fix.
- The
Did you forget to include 'void' in your type argument to 'Promise'? errors aren't related to these.
- There's some conflation in the concerns.
- "
void reform. - How common was the parameter optionality issue?
- Pretty common.
- It's been this way for years.
- We have complaints about why isn't it stricter?
- Most feedback is positive - they're happy to be broken.
- We made trailing void optional just to be ready for this fix.
- Tried to solve this with new inference, but causes more problems than it's worth.
- Everything that's "more elegant" is very messy and counter to our inference strategies.
- 4.1 is otherwise not that breaky, and this is pretty mechanical.
- Pre-seed some StackOverflow question about it to help users find the right answer?
- It seems like overall, we want to keep this in.
abstract Constructor Types
#36392
- Allows us to prefix construct signatures with the
abstract keyword. abstract new () => any.- Today in
lib.d.ts, we have Constructor.
- Today, you can write a mixin using the
Constructor type. - But
Constructor doesn't allow abstract classes, so you can't write a mixin on abstract classes.
- It is okay to assign a concrete constructor to an abstract constructor.
- It is not okay to assign an abstract constructor to a concrete constructor.
- When extending from an
abstract constructor, you must declare it to be abstract.
- You need to do this because there's no way to know which members are or are not getting implemented.
- The construct signature doesn't signal which instance-side members are abstract.
- Kind of like
readonly - promising you won't do something with the type (i.e. construct it directly). - Out of time.
Conditional Spread is More Prone to Losing
| undefined#41418
xincludesundefinedinfromAnnotation.undefinedormissing.undefinedmeans we can't do anything.undefinedto be written to an index signature.undefinedin their type.obj2is not assignable toa, butqis assignable toa.Backing out
resolveChanges#41497
Did you forget to include 'void' in your type argument to 'Promise'?errors aren't related to these.voidreform.abstractConstructor Types#36392
abstractkeyword.abstract new () => any.lib.d.ts, we haveConstructor.Constructortype.Constructordoesn't allowabstractclasses, so you can't write a mixin on abstract classes.abstractconstructor, you must declare it to beabstract.readonly- promising you won't do something with the type (i.e. construct it directly).