Closed
Description
@andrewbranch took notes for the first two items of this meeting
Check for Array Constraints When Instantiating Mapped Types with any
- Noticed an issue with
Promise.all
:Promise.all
onany
producesPromise<Record<string, any>>
#46169async function foo(x: any) { let abc = await Promise.all(x); let oops: any[] = abc; // Error: Type '{ [x: string]: any; }' is missing the following properties from type 'any[]': length, pop, push, concat, and 26 more.(2 }
- When you plug an
any
into a mapped type, you get a Record fromstring
toany
- Due to changes to
Promise.all
in 4.5 - Proposal: if the thing we’re putting into
T
here is array-like, the output should be array-like too.declare function f<T extends unknown[]>(x: T): { [K in keyof T]: T[K] } f([1, 2, 3]) f(null as any)
- Check for array types when instantiating mapped type constraints with
any
#46218 - Basically a one-liner
- Doesn't break any tests anywhere
- Check for array types when instantiating mapped type constraints with
- What's the equivalent of an any that's known to be an array? Or a tuple with a known arity?
- With
Almost feels like you should map over the constraint and return that?
declare function f<T extends [unknown, unknown]>(x: T): { [K in keyof T]: T[K] } let x = f([1, 2,]) let y = f(null as any)
- If an
any
flows in, should you really say the output has the right arity?
- If an
- Next issue:
type Arrayish<T extends unknown[]> = { [K in keyof T]: T[K] }; type Objectish<T extends unknown> = { [K in keyof T]: T[K] }; // Should always produce array types, but can't get this to work type IndirectArrayish<U extends unknown[]> = Objectish<U>; declare let x: IndirectArrayish<any>;
- Actually this would be really weird - the constraint type should maybe be considered local knowledge; a local artifact of
Arrayish
orObjectish
. Is it a dynamic attribute of the instantiation? It would need to be carried in the type, and that's not how type instantiation works.- When we check
Objectish<U>
, we make sure thatU
extendsunknown
. Then, we instantiate withU
, but there's no knowledge - well, I guess there could be - let's take it offline
- When we check
- Talking about generalizing this from arrays to tuples: it seems like you could generalize this to any base constraint.
type Objectish<T extends { x: string}> = { [K in keyof T]: T[K] }; declare let x: Objectish<any>; // could be { x: string } instead of { [key: string]: any }?
- Actually this would be really weird - the constraint type should maybe be considered local knowledge; a local artifact of
strictJsxAttributeChecks
- Resistance to having a flag for this. Is it enough bang for the buck?
- The loose checking of dashed properties is old kludge designed for
data-*
. You can declare that now. We could add that signature to React typings and remove the hardcoded support from the compiler instead of flagging it at all. - Whatever we do, the user could add support back on their own with the global JSX namespace.
- Are we willing to take an external PR so we can experiment and see what breaks?
- Still don't want a flag.
- Maybe open to doing it unflagged if we see a lot of good come from it.
- PRs welcomed, not committed.
Conditions of Destructured Variables
type Action =
| { type: 'A', payload: number }
| { type: 'B': payload: string };
function reducer(state: Whatever, { type, payload }: Action) {
switch (type) {
case 'A':
payload.toFixed();
break;
case 'B':
payload.toUpperCase();
break;
}
}
-
Want to be able to narrow
payload
based on narrowingtype
. -
PR has this working.
-
When destructuring a parameter, we know that there are no aliasing situations. That helps with the implementation.
- If you start out with an
action
and then destructure, that can be tricky.
- If you start out with an
-
We can narrow the group depending on whether it comes from a
const
or parameter, and the declared type of the binding pattern as a whole is a union, then we see if we can narrow the types based on other destructured properties.- We create a pseudo-object type which
kind
can discriminate on. - Binding element is now a pseudo reference.
- We create a pseudo-object type which
-
Does modification reset narrowing?
- Yes, only
const
s and unmodified parameters.
- Yes, only
-
Relies on these properties coming from the same destructuring pattern.
-
So this doesn't work?
const { kind } = action; const { payload } = action; if (kind === "A") { // payload ideally should be narrowed here. }
- No - no ways we can do that.
- However, we are able to narrow
action
bykind
, which is nice. - Feels like a weird limitation.