From 00e3926c48c050b4e859072f58e6189d05593054 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Tue, 30 Aug 2022 17:55:17 +0200 Subject: [PATCH 1/3] Defer distributing index over generic object types --- src/compiler/checker.ts | 3 ++ ...tWithIndexSignatureWithNonNullable.symbols | 39 +++++++++++++++++++ ...intWithIndexSignatureWithNonNullable.types | 24 ++++++++++++ ...traintWithIndexSignatureWithNonNullable.ts | 16 ++++++++ 4 files changed, 82 insertions(+) create mode 100644 tests/baselines/reference/mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.symbols create mode 100644 tests/baselines/reference/mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.types create mode 100644 tests/cases/compiler/mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 01fc87bae36a4..70daadb092357 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15903,6 +15903,9 @@ namespace ts { } function distributeIndexOverObjectType(objectType: Type, indexType: Type, writing: boolean) { + if (shouldDeferIndexType(objectType)) { + return; + } // (T | U)[K] -> T[K] | U[K] (reading) // (T | U)[K] -> T[K] & U[K] (writing) // (T & U)[K] -> T[K] & U[K] diff --git a/tests/baselines/reference/mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.symbols b/tests/baselines/reference/mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.symbols new file mode 100644 index 0000000000000..c94bc76ef60a3 --- /dev/null +++ b/tests/baselines/reference/mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.symbols @@ -0,0 +1,39 @@ +=== tests/cases/compiler/mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts === +interface StateSchema { +>StateSchema : Symbol(StateSchema, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 0, 0)) + + states?: { +>states : Symbol(StateSchema.states, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 0, 23)) + + [key: string]: StateSchema; +>key : Symbol(key, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 2, 5)) +>StateSchema : Symbol(StateSchema, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 0, 0)) + + }; +} + +declare class StateNode { +>StateNode : Symbol(StateNode, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 4, 1)) +>TStateSchema : Symbol(TStateSchema, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 6, 24)) +>StateSchema : Symbol(StateSchema, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 0, 0)) + + schema: TStateSchema; +>schema : Symbol(StateNode.schema, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 6, 59)) +>TStateSchema : Symbol(TStateSchema, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 6, 24)) +} + +type StateNodesConfig = { +>StateNodesConfig : Symbol(StateNodesConfig, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 8, 1)) +>TStateSchema : Symbol(TStateSchema, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 10, 22)) +>StateSchema : Symbol(StateSchema, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 0, 0)) + + [K in keyof TStateSchema["states"]]: StateNode[K]>; +>K : Symbol(K, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 11, 3)) +>TStateSchema : Symbol(TStateSchema, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 10, 22)) +>StateNode : Symbol(StateNode, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 4, 1)) +>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --)) +>TStateSchema : Symbol(TStateSchema, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 10, 22)) +>K : Symbol(K, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 11, 3)) + +}; + diff --git a/tests/baselines/reference/mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.types b/tests/baselines/reference/mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.types new file mode 100644 index 0000000000000..324becfe6b1cf --- /dev/null +++ b/tests/baselines/reference/mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.types @@ -0,0 +1,24 @@ +=== tests/cases/compiler/mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts === +interface StateSchema { + states?: { +>states : { [key: string]: StateSchema; } | undefined + + [key: string]: StateSchema; +>key : string + + }; +} + +declare class StateNode { +>StateNode : StateNode + + schema: TStateSchema; +>schema : TStateSchema +} + +type StateNodesConfig = { +>StateNodesConfig : StateNodesConfig + + [K in keyof TStateSchema["states"]]: StateNode[K]>; +}; + diff --git a/tests/cases/compiler/mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts b/tests/cases/compiler/mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts new file mode 100644 index 0000000000000..025170356f969 --- /dev/null +++ b/tests/cases/compiler/mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts @@ -0,0 +1,16 @@ +// @noEmit: true +// @strict: true + +interface StateSchema { + states?: { + [key: string]: StateSchema; + }; +} + +declare class StateNode { + schema: TStateSchema; +} + +type StateNodesConfig = { + [K in keyof TStateSchema["states"]]: StateNode[K]>; +}; From 2ba9ff19c841c8f9fc6ebc361464a10a9008f529 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 31 Aug 2022 07:50:47 +0200 Subject: [PATCH 2/3] Only check if the index type should be deferred for intersection types --- src/compiler/checker.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 70daadb092357..f10e4f92e0494 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15903,13 +15903,10 @@ namespace ts { } function distributeIndexOverObjectType(objectType: Type, indexType: Type, writing: boolean) { - if (shouldDeferIndexType(objectType)) { - return; - } // (T | U)[K] -> T[K] | U[K] (reading) // (T | U)[K] -> T[K] & U[K] (writing) // (T & U)[K] -> T[K] & U[K] - if (objectType.flags & TypeFlags.UnionOrIntersection) { + if (objectType.flags & TypeFlags.Union || objectType.flags & TypeFlags.Intersection && !shouldDeferIndexType(objectType)) { const types = map((objectType as UnionOrIntersectionType).types, t => getSimplifiedType(getIndexedAccessType(t, indexType), writing)); return objectType.flags & TypeFlags.Intersection || writing ? getIntersectionType(types) : getUnionType(types); } From 873dfea5d2e871c7150e302c8ffd50344ed1a727 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 1 Sep 2022 12:53:40 +0200 Subject: [PATCH 3/3] Add an additional test case --- ...tWithIndexSignatureWithNonNullable.symbols | 39 ---------- ...intWithIndexSignatureWithNonNullable.types | 24 ------ ...ithNullableGenericIndexedAccessArg.symbols | 77 +++++++++++++++++++ ...eWithNullableGenericIndexedAccessArg.types | 49 ++++++++++++ ...bleWithNullableGenericIndexedAccessArg.ts} | 17 ++++ 5 files changed, 143 insertions(+), 63 deletions(-) delete mode 100644 tests/baselines/reference/mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.symbols delete mode 100644 tests/baselines/reference/mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.types create mode 100644 tests/baselines/reference/nonNullableWithNullableGenericIndexedAccessArg.symbols create mode 100644 tests/baselines/reference/nonNullableWithNullableGenericIndexedAccessArg.types rename tests/cases/compiler/{mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts => nonNullableWithNullableGenericIndexedAccessArg.ts} (50%) diff --git a/tests/baselines/reference/mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.symbols b/tests/baselines/reference/mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.symbols deleted file mode 100644 index c94bc76ef60a3..0000000000000 --- a/tests/baselines/reference/mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.symbols +++ /dev/null @@ -1,39 +0,0 @@ -=== tests/cases/compiler/mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts === -interface StateSchema { ->StateSchema : Symbol(StateSchema, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 0, 0)) - - states?: { ->states : Symbol(StateSchema.states, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 0, 23)) - - [key: string]: StateSchema; ->key : Symbol(key, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 2, 5)) ->StateSchema : Symbol(StateSchema, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 0, 0)) - - }; -} - -declare class StateNode { ->StateNode : Symbol(StateNode, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 4, 1)) ->TStateSchema : Symbol(TStateSchema, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 6, 24)) ->StateSchema : Symbol(StateSchema, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 0, 0)) - - schema: TStateSchema; ->schema : Symbol(StateNode.schema, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 6, 59)) ->TStateSchema : Symbol(TStateSchema, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 6, 24)) -} - -type StateNodesConfig = { ->StateNodesConfig : Symbol(StateNodesConfig, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 8, 1)) ->TStateSchema : Symbol(TStateSchema, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 10, 22)) ->StateSchema : Symbol(StateSchema, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 0, 0)) - - [K in keyof TStateSchema["states"]]: StateNode[K]>; ->K : Symbol(K, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 11, 3)) ->TStateSchema : Symbol(TStateSchema, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 10, 22)) ->StateNode : Symbol(StateNode, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 4, 1)) ->NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --)) ->TStateSchema : Symbol(TStateSchema, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 10, 22)) ->K : Symbol(K, Decl(mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts, 11, 3)) - -}; - diff --git a/tests/baselines/reference/mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.types b/tests/baselines/reference/mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.types deleted file mode 100644 index 324becfe6b1cf..0000000000000 --- a/tests/baselines/reference/mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.types +++ /dev/null @@ -1,24 +0,0 @@ -=== tests/cases/compiler/mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts === -interface StateSchema { - states?: { ->states : { [key: string]: StateSchema; } | undefined - - [key: string]: StateSchema; ->key : string - - }; -} - -declare class StateNode { ->StateNode : StateNode - - schema: TStateSchema; ->schema : TStateSchema -} - -type StateNodesConfig = { ->StateNodesConfig : StateNodesConfig - - [K in keyof TStateSchema["states"]]: StateNode[K]>; -}; - diff --git a/tests/baselines/reference/nonNullableWithNullableGenericIndexedAccessArg.symbols b/tests/baselines/reference/nonNullableWithNullableGenericIndexedAccessArg.symbols new file mode 100644 index 0000000000000..a461d361eedcc --- /dev/null +++ b/tests/baselines/reference/nonNullableWithNullableGenericIndexedAccessArg.symbols @@ -0,0 +1,77 @@ +=== tests/cases/compiler/nonNullableWithNullableGenericIndexedAccessArg.ts === +// repro from #50539 + +interface StateSchema { +>StateSchema : Symbol(StateSchema, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 0, 0)) + + states?: { +>states : Symbol(StateSchema.states, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 2, 23)) + + [key: string]: StateSchema; +>key : Symbol(key, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 4, 5)) +>StateSchema : Symbol(StateSchema, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 0, 0)) + + }; +} + +declare class StateNode { +>StateNode : Symbol(StateNode, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 6, 1)) +>TStateSchema : Symbol(TStateSchema, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 8, 24)) +>StateSchema : Symbol(StateSchema, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 0, 0)) + + schema: TStateSchema; +>schema : Symbol(StateNode.schema, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 8, 59)) +>TStateSchema : Symbol(TStateSchema, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 8, 24)) +} + +type StateNodesConfig = { +>StateNodesConfig : Symbol(StateNodesConfig, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 10, 1)) +>TStateSchema : Symbol(TStateSchema, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 12, 22)) +>StateSchema : Symbol(StateSchema, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 0, 0)) + + [K in keyof TStateSchema["states"]]: StateNode[K]>; +>K : Symbol(K, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 13, 3)) +>TStateSchema : Symbol(TStateSchema, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 12, 22)) +>StateNode : Symbol(StateNode, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 6, 1)) +>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --)) +>TStateSchema : Symbol(TStateSchema, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 12, 22)) +>K : Symbol(K, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 13, 3)) + +}; + +// repro from #50539#issuecomment-1234067835 + +type Ordering = { +>Ordering : Symbol(Ordering, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 14, 2)) +>TOrderBy : Symbol(TOrderBy, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 18, 14)) + + orderBy: TOrderBy +>orderBy : Symbol(orderBy, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 18, 42)) +>TOrderBy : Symbol(TOrderBy, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 18, 14)) +} + +type Query = { +>Query : Symbol(Query, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 20, 1)) +>TOrderBy : Symbol(TOrderBy, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 22, 11)) + + order?: Ordering +>order : Symbol(order, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 22, 39)) +>Ordering : Symbol(Ordering, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 14, 2)) +>TOrderBy : Symbol(TOrderBy, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 22, 11)) +} + +type QueryHandler< +>QueryHandler : Symbol(QueryHandler, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 24, 1)) + + TQuery extends Query, +>TQuery : Symbol(TQuery, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 26, 18)) +>Query : Symbol(Query, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 20, 1)) +>TOrderBy : Symbol(TOrderBy, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 27, 35)) + + TOrderBy extends string = NonNullable["orderBy"] +>TOrderBy : Symbol(TOrderBy, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 27, 35)) +>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --)) +>TQuery : Symbol(TQuery, Decl(nonNullableWithNullableGenericIndexedAccessArg.ts, 26, 18)) + +> = {} + diff --git a/tests/baselines/reference/nonNullableWithNullableGenericIndexedAccessArg.types b/tests/baselines/reference/nonNullableWithNullableGenericIndexedAccessArg.types new file mode 100644 index 0000000000000..f2bbff47ada4c --- /dev/null +++ b/tests/baselines/reference/nonNullableWithNullableGenericIndexedAccessArg.types @@ -0,0 +1,49 @@ +=== tests/cases/compiler/nonNullableWithNullableGenericIndexedAccessArg.ts === +// repro from #50539 + +interface StateSchema { + states?: { +>states : { [key: string]: StateSchema; } | undefined + + [key: string]: StateSchema; +>key : string + + }; +} + +declare class StateNode { +>StateNode : StateNode + + schema: TStateSchema; +>schema : TStateSchema +} + +type StateNodesConfig = { +>StateNodesConfig : StateNodesConfig + + [K in keyof TStateSchema["states"]]: StateNode[K]>; +}; + +// repro from #50539#issuecomment-1234067835 + +type Ordering = { +>Ordering : Ordering + + orderBy: TOrderBy +>orderBy : TOrderBy +} + +type Query = { +>Query : Query + + order?: Ordering +>order : Ordering | undefined +} + +type QueryHandler< +>QueryHandler : QueryHandler + + TQuery extends Query, + TOrderBy extends string = NonNullable["orderBy"] +> = {} + diff --git a/tests/cases/compiler/mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts b/tests/cases/compiler/nonNullableWithNullableGenericIndexedAccessArg.ts similarity index 50% rename from tests/cases/compiler/mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts rename to tests/cases/compiler/nonNullableWithNullableGenericIndexedAccessArg.ts index 025170356f969..8b8d4dc0e24ca 100644 --- a/tests/cases/compiler/mappedTypeOverNullableConstraintWithIndexSignatureWithNonNullable.ts +++ b/tests/cases/compiler/nonNullableWithNullableGenericIndexedAccessArg.ts @@ -1,6 +1,8 @@ // @noEmit: true // @strict: true +// repro from #50539 + interface StateSchema { states?: { [key: string]: StateSchema; @@ -14,3 +16,18 @@ declare class StateNode { type StateNodesConfig = { [K in keyof TStateSchema["states"]]: StateNode[K]>; }; + +// repro from #50539#issuecomment-1234067835 + +type Ordering = { + orderBy: TOrderBy +} + +type Query = { + order?: Ordering +} + +type QueryHandler< + TQuery extends Query, + TOrderBy extends string = NonNullable["orderBy"] +> = {}