Description
Generic object spread and spread types (continued)
-
Back in Add spread/rest higher-order types operator #10727, we speculated that we could have a new kind of type to describe the behavior of spread on generic types.
-
Seemed pretty complicated to come up with a new rules on higher order spread types so we waited on it.
-
Now that our type system has become pretty rich, we started wondering whether we could start to describe spread types in terms of conditional types and mapped types.
-
We can kind of do that, but there are certain caveats: our spread functionality tries to guess the "right" behavior to reflect the runtime.
-
We don't copy methods, we avoid set-only accessors, whatever.
-
Now if we want to do this in a higher-order sense (i.e. on generics), you need a way to select the keys that spread would actually copy those over.
-
So we thought about an
own
operator, but then you get into some unintuitive cases. For example, you'd think that for the following:function foo<T>(obj1: T, obj2: T) { return { ...obj1, ...obj2 }; }
you'd get something assignable to a
T
. But no, instead you'd get something like aSpread<Own<T>, Own<T>>
- which is not aT
, and is not even anOwn<T>
without some extra work. So this is not great. -
Up until now,
Object.assign
just returned intersections.- But spreads have almost identical semantics to
Object.assign
! - While it's not correct to return intersections, by and large it's been good enough.
- So what we do now is that when you have a "zero-order" type (i.e. a non-generic type), we just do what we do today by constructing a new object type; but if you have a generic type, we'll stop and intersect with the current run of spreads.
- So
...{ x: 100}, ...{ y: "hello" }, ...z
wherez
has typeT
is{ x: number, y: string } & T
.
- But spreads have almost identical semantics to
Generic object rest
-
The natural question arises: what about object rest.
-
With Generic object rest variables and parameters #28312, if
obj
has typeT extends { foo: string }
, for the following code:function f<T extends { foo: string }>(obj: T) { let { foo, ...rest } = obj; return rest; }
now
f
returns the typePick<T, Exclude<keyof T, "foo">>
. -
There was some work that needed to be done with symbols.
- Wait, symbols aren't enumerable.
- Does that matter?
- [[Discussion]]
-
What about the higher order components which are one of the most in-demand use-cases here?
-
Doesn't seem to "work" right
function excludeTag< T extends { tag: string } & U, U extends>( obj: T) { let { foo, ...rest } = obj; let blah: U = rest; // error! }
-
-
People might try to use
Pick<T, Exclude<keyof T, keyof U>>
and it still won't work. -
Sounds like we need subtraction types!
- Even though we kind of sort of have them with
Exclude
.
- Even though we kind of sort of have them with
-
[[Discussion about subtraction types and negated types]]
Partial Type Argument Inference (revisited)
- We put out Implement partial type argument inference using the _ sigil #26349 back in August
- ~6 weeks ago when we last talked about partial type argument inference, we decided not to do anything since we couldn't pick a sigil.
- Recently Flow implemented the feature and picked the
_
character. - This is the second-most voted PR on our repo.
- Seems like there are legitimate use-cases and C# is looking at this; so what's the sigil?
- Problem with
_
is that it's a legitimate use-case- BigTSQuery says that there are a couple of uses of
_
but explicit type arguments are rare; so contextually reserving it is definitely overkill.
- BigTSQuery says that there are a couple of uses of
- Conclusion:
Structurally identical-looking Derived<T>
not assignable to Base<T>
- We fixed the specific issue, but there are other issues here.
Built-in base configs
- Do we want to ship any default configs ourselves.
- We can ship a set of defaults for well-known workloads (e.g. mixed JS & TS)
- But your defaults for Babel aren't related to defaults for strictness.
- So now you need multiple inheritance to combine multiple tsconfigs!?
- Lots of potential to break.
- Scaffolding tools already do it all for you anyway.
- Not clear if it's any more discoverable than the options themselves.