Closed
Description
Conditional Spread is More Prone to Losing | undefined
declare let bool: boolean;
const obj = {
...bool && { x: 'x' },
...bool && { y: 'y' },
};
const x: 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.
declare let r: { [key: string]: number };
let fromExpression = { ...bool && { x: 3 } };
r = { ...fromExpression }; // Ok
declare let fromAnnotation: { x?: number };
r = { ...fromAnnotation }; // Error: Type 'undefined' is not assignable to type 'number'.
- Type from
x
includesundefined
infromAnnotation
. - 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.
declare let z: { a: string } | {};
const zz = { ...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
ormissing
.- 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.
const obj2 = { m: Math.random() > 0.5 ? undefined: "" };
const q: { m?: string } = obj2;
const a: { [s: string]: string } = q;
if ("m" in a) {
a["m"].toUpperCase();
}
- With the optionality rule,
obj2
is not assignable toa
, butq
is assignable toa
.- Non-transitivity has always been the case ¯\_(ツ)_/¯
- Continue next week?
Backing out resolve
Changes
- 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.
- The
- 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
- Allows us to prefix construct signatures with the
abstract
keyword. abstract new () => any
.- Today in
lib.d.ts
, we haveConstructor
.- Today, you can write a mixin using the
Constructor
type. - But
Constructor
doesn't allowabstract
classes, so you can't write a mixin on abstract classes.
- Today, you can write a mixin using the
- 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 beabstract
.- 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.