From 5797b1fce06e02930da4d7f8ccaeb3f70effc674 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sat, 28 Sep 2024 10:11:32 +0200 Subject: [PATCH] Use lower bound of index types as their constraints when they are applied to indexed access types with non-generic root object type --- src/compiler/checker.ts | 23 +- .../constraintWithIndexedAccess.errors.txt | 50 +---- ...exTypeConstraintWithIndexedAccess1.symbols | 207 ++++++++++++++++++ ...ndexTypeConstraintWithIndexedAccess1.types | 196 +++++++++++++++++ .../intersectionsOfLargeUnions.types | 2 +- .../intersectionsOfLargeUnions2.types | 2 +- .../indexTypeConstraintWithIndexedAccess1.ts | 73 ++++++ 7 files changed, 503 insertions(+), 50 deletions(-) create mode 100644 tests/baselines/reference/indexTypeConstraintWithIndexedAccess1.symbols create mode 100644 tests/baselines/reference/indexTypeConstraintWithIndexedAccess1.types create mode 100644 tests/cases/compiler/indexTypeConstraintWithIndexedAccess1.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 88448475aaa67..37f6ef998ea2d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14393,7 +14393,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { setStructuredTypeMembers(type, members, emptyArray, emptyArray, indexInfos); } - // Return the lower bound of the key type in a mapped type. Intuitively, the lower + // Return the lower bound of the key or index type. Intuitively, the lower // bound includes those keys that are known to always be present, for example because // because of constraints on type parameters (e.g. 'keyof T' for a constrained T). function getLowerBoundOfKeyType(type: Type): Type { @@ -14934,11 +14934,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getBaseConstraintOfType(type: Type): Type | undefined { - if (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) || isGenericTupleType(type)) { - const constraint = getResolvedBaseConstraint(type as InstantiableType | UnionOrIntersectionType); + if (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.UnionOrIntersection | TypeFlags.TemplateLiteral | TypeFlags.StringMapping | TypeFlags.Index) || isGenericTupleType(type)) { + const constraint = getResolvedBaseConstraint(type as InstantiableType | UnionOrIntersectionType | IndexType); return constraint !== noConstraintType && constraint !== circularConstraintType ? constraint : undefined; } - return type.flags & TypeFlags.Index ? stringNumberSymbolType : undefined; + return undefined; } /** @@ -15036,6 +15036,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { undefined; } if (t.flags & TypeFlags.Index) { + const type = (t as IndexType).type; + if (type.flags & TypeFlags.IndexedAccess) { + let objectType = (type as IndexedAccessType).objectType; + while (objectType.flags & TypeFlags.IndexedAccess) { + objectType = (objectType as IndexedAccessType).objectType; + } + if (!isGenericObjectType(objectType)) { + const consraint = getLowerBoundOfKeyType(t); + if (!(consraint.flags & TypeFlags.Never)) { + return consraint; + } + } + } return stringNumberSymbolType; } if (t.flags & TypeFlags.TemplateLiteral) { @@ -23503,7 +23516,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else if (sourceFlags & TypeFlags.Index) { const isDeferredMappedIndex = shouldDeferIndexType((source as IndexType).type, (source as IndexType).indexFlags) && getObjectFlags((source as IndexType).type) & ObjectFlags.Mapped; - if (result = isRelatedTo(stringNumberSymbolType, target, RecursionFlags.Source, reportErrors && !isDeferredMappedIndex)) { + if (result = isRelatedTo(getBaseConstraintOfType(source)!, target, RecursionFlags.Source, reportErrors && !isDeferredMappedIndex)) { return result; } if (isDeferredMappedIndex) { diff --git a/tests/baselines/reference/constraintWithIndexedAccess.errors.txt b/tests/baselines/reference/constraintWithIndexedAccess.errors.txt index 11641a24b4fce..6c0274b82b5a2 100644 --- a/tests/baselines/reference/constraintWithIndexedAccess.errors.txt +++ b/tests/baselines/reference/constraintWithIndexedAccess.errors.txt @@ -1,19 +1,3 @@ -constraintWithIndexedAccess.ts(23,90): error TS2344: Type 'TypeHardcodedAsParameterWithoutReturnType' does not satisfy the constraint '(...args: any) => any'. - Type 'DataFetchFns[T][keyof DataFetchFns[T]]' is not assignable to type '(...args: any) => any'. - Type 'DataFetchFns[T][string] | DataFetchFns[T][number] | DataFetchFns[T][symbol]' is not assignable to type '(...args: any) => any'. - Type 'DataFetchFns[T][string]' is not assignable to type '(...args: any) => any'. -constraintWithIndexedAccess.ts(24,102): error TS2344: Type 'DataFetchFns[T][F]' does not satisfy the constraint '(...args: any) => any'. - Type 'DataFetchFns[T][keyof DataFetchFns[T]]' is not assignable to type '(...args: any) => any'. - Type 'DataFetchFns[T][string] | DataFetchFns[T][number] | DataFetchFns[T][symbol]' is not assignable to type '(...args: any) => any'. - Type 'DataFetchFns[T][string]' is not assignable to type '(...args: any) => any'. -constraintWithIndexedAccess.ts(26,103): error TS2344: Type 'VehicleSelector[F]' does not satisfy the constraint '(...args: any) => any'. - Type 'VehicleSelector[keyof DataFetchFns[T]]' is not assignable to type '(...args: any) => any'. - Type 'VehicleSelector[string] | VehicleSelector[number] | VehicleSelector[symbol]' is not assignable to type '(...args: any) => any'. - Type 'VehicleSelector[string]' is not assignable to type '(...args: any) => any'. -constraintWithIndexedAccess.ts(27,102): error TS2344: Type 'DataFetchFns[T][F]' does not satisfy the constraint '(...args: any) => any'. - Type 'DataFetchFns[T][keyof DataFetchFns[T]]' is not assignable to type '(...args: any) => any'. - Type 'DataFetchFns[T][string] | DataFetchFns[T][number] | DataFetchFns[T][symbol]' is not assignable to type '(...args: any) => any'. - Type 'DataFetchFns[T][string]' is not assignable to type '(...args: any) => any'. constraintWithIndexedAccess.ts(28,102): error TS2344: Type 'DataFetchFns[T][T]' does not satisfy the constraint '(...args: any) => any'. Type 'DataFetchFns[T]["Boat"] | DataFetchFns[T]["Plane"]' is not assignable to type '(...args: any) => any'. Type 'DataFetchFns[T]["Boat"]' is not assignable to type '(...args: any) => any'. @@ -21,13 +5,13 @@ constraintWithIndexedAccess.ts(28,102): error TS2536: Type 'T' cannot be used to constraintWithIndexedAccess.ts(29,102): error TS2536: Type 'F' cannot be used to index type 'DataFetchFns'. constraintWithIndexedAccess.ts(29,102): error TS2344: Type 'DataFetchFns[F][F]' does not satisfy the constraint '(...args: any) => any'. Type 'DataFetchFns[F][keyof DataFetchFns[T]]' is not assignable to type '(...args: any) => any'. - Type 'DataFetchFns[F][string] | DataFetchFns[F][number] | DataFetchFns[F][symbol]' is not assignable to type '(...args: any) => any'. - Type 'DataFetchFns[F][string]' is not assignable to type '(...args: any) => any'. - Type 'DataFetchFns[keyof DataFetchFns[T]][string]' is not assignable to type '(...args: any) => any'. + Type 'DataFetchFns[F]["requiresLicense"] | DataFetchFns[F]["maxGroundSpeed"] | DataFetchFns[F]["name"]' is not assignable to type '(...args: any) => any'. + Type 'DataFetchFns[F]["requiresLicense"]' is not assignable to type '(...args: any) => any'. + Type 'DataFetchFns[keyof DataFetchFns[T]]["requiresLicense"]' is not assignable to type '(...args: any) => any'. constraintWithIndexedAccess.ts(29,102): error TS2536: Type 'F' cannot be used to index type 'DataFetchFns[F]'. -==== constraintWithIndexedAccess.ts (9 errors) ==== +==== constraintWithIndexedAccess.ts (5 errors) ==== // #52399 type DataFetchFns = { Boat: { @@ -51,30 +35,10 @@ constraintWithIndexedAccess.ts(29,102): error TS2536: Type 'F' cannot be used to export type returnTypeOfFunctions = ReturnType; //string | number | boolean as expected export type SucceedingCombo = ReturnType>; export type FailingCombo = ReturnType>; - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2344: Type 'TypeHardcodedAsParameterWithoutReturnType' does not satisfy the constraint '(...args: any) => any'. -!!! error TS2344: Type 'DataFetchFns[T][keyof DataFetchFns[T]]' is not assignable to type '(...args: any) => any'. -!!! error TS2344: Type 'DataFetchFns[T][string] | DataFetchFns[T][number] | DataFetchFns[T][symbol]' is not assignable to type '(...args: any) => any'. -!!! error TS2344: Type 'DataFetchFns[T][string]' is not assignable to type '(...args: any) => any'. export type TypeHardcodedAsParameter = ReturnType; - ~~~~~~~~~~~~~~~~~~ -!!! error TS2344: Type 'DataFetchFns[T][F]' does not satisfy the constraint '(...args: any) => any'. -!!! error TS2344: Type 'DataFetchFns[T][keyof DataFetchFns[T]]' is not assignable to type '(...args: any) => any'. -!!! error TS2344: Type 'DataFetchFns[T][string] | DataFetchFns[T][number] | DataFetchFns[T][symbol]' is not assignable to type '(...args: any) => any'. -!!! error TS2344: Type 'DataFetchFns[T][string]' is not assignable to type '(...args: any) => any'. type VehicleSelector = DataFetchFns[T]; export type TypeHardcodedAsParameter2 = ReturnType[F]>; - ~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2344: Type 'VehicleSelector[F]' does not satisfy the constraint '(...args: any) => any'. -!!! error TS2344: Type 'VehicleSelector[keyof DataFetchFns[T]]' is not assignable to type '(...args: any) => any'. -!!! error TS2344: Type 'VehicleSelector[string] | VehicleSelector[number] | VehicleSelector[symbol]' is not assignable to type '(...args: any) => any'. -!!! error TS2344: Type 'VehicleSelector[string]' is not assignable to type '(...args: any) => any'. export type TypeGeneric1 = ReturnType; - ~~~~~~~~~~~~~~~~~~ -!!! error TS2344: Type 'DataFetchFns[T][F]' does not satisfy the constraint '(...args: any) => any'. -!!! error TS2344: Type 'DataFetchFns[T][keyof DataFetchFns[T]]' is not assignable to type '(...args: any) => any'. -!!! error TS2344: Type 'DataFetchFns[T][string] | DataFetchFns[T][number] | DataFetchFns[T][symbol]' is not assignable to type '(...args: any) => any'. -!!! error TS2344: Type 'DataFetchFns[T][string]' is not assignable to type '(...args: any) => any'. export type TypeGeneric2 = ReturnType; // error ~~~~~~~~~~~~~~~~~~ !!! error TS2344: Type 'DataFetchFns[T][T]' does not satisfy the constraint '(...args: any) => any'. @@ -88,9 +52,9 @@ constraintWithIndexedAccess.ts(29,102): error TS2536: Type 'F' cannot be used to ~~~~~~~~~~~~~~~~~~ !!! error TS2344: Type 'DataFetchFns[F][F]' does not satisfy the constraint '(...args: any) => any'. !!! error TS2344: Type 'DataFetchFns[F][keyof DataFetchFns[T]]' is not assignable to type '(...args: any) => any'. -!!! error TS2344: Type 'DataFetchFns[F][string] | DataFetchFns[F][number] | DataFetchFns[F][symbol]' is not assignable to type '(...args: any) => any'. -!!! error TS2344: Type 'DataFetchFns[F][string]' is not assignable to type '(...args: any) => any'. -!!! error TS2344: Type 'DataFetchFns[keyof DataFetchFns[T]][string]' is not assignable to type '(...args: any) => any'. +!!! error TS2344: Type 'DataFetchFns[F]["requiresLicense"] | DataFetchFns[F]["maxGroundSpeed"] | DataFetchFns[F]["name"]' is not assignable to type '(...args: any) => any'. +!!! error TS2344: Type 'DataFetchFns[F]["requiresLicense"]' is not assignable to type '(...args: any) => any'. +!!! error TS2344: Type 'DataFetchFns[keyof DataFetchFns[T]]["requiresLicense"]' is not assignable to type '(...args: any) => any'. ~~~~~~~~~~~~~~~~~~ !!! error TS2536: Type 'F' cannot be used to index type 'DataFetchFns[F]'. \ No newline at end of file diff --git a/tests/baselines/reference/indexTypeConstraintWithIndexedAccess1.symbols b/tests/baselines/reference/indexTypeConstraintWithIndexedAccess1.symbols new file mode 100644 index 0000000000000..ed68ef8db00d7 --- /dev/null +++ b/tests/baselines/reference/indexTypeConstraintWithIndexedAccess1.symbols @@ -0,0 +1,207 @@ +//// [tests/cases/compiler/indexTypeConstraintWithIndexedAccess1.ts] //// + +=== indexTypeConstraintWithIndexedAccess1.ts === +// https://github.com/microsoft/TypeScript/issues/21760 + +interface IExample { +>IExample : Symbol(IExample, Decl(indexTypeConstraintWithIndexedAccess1.ts, 0, 0)) + + foo: { +>foo : Symbol(IExample.foo, Decl(indexTypeConstraintWithIndexedAccess1.ts, 2, 20)) + + bar: { +>bar : Symbol(bar, Decl(indexTypeConstraintWithIndexedAccess1.ts, 3, 10)) + + baz: number; +>baz : Symbol(baz, Decl(indexTypeConstraintWithIndexedAccess1.ts, 4, 14)) + } + } +} + +type F = < +>F : Symbol(F, Decl(indexTypeConstraintWithIndexedAccess1.ts, 8, 1)) + + name extends keyof IExample, +>name : Symbol(name, Decl(indexTypeConstraintWithIndexedAccess1.ts, 10, 10)) +>IExample : Symbol(IExample, Decl(indexTypeConstraintWithIndexedAccess1.ts, 0, 0)) + + val extends keyof IExample[name] +>val : Symbol(val, Decl(indexTypeConstraintWithIndexedAccess1.ts, 11, 32)) +>IExample : Symbol(IExample, Decl(indexTypeConstraintWithIndexedAccess1.ts, 0, 0)) +>name : Symbol(name, Decl(indexTypeConstraintWithIndexedAccess1.ts, 10, 10)) + +>() => IExample[name][val]['baz']; +>IExample : Symbol(IExample, Decl(indexTypeConstraintWithIndexedAccess1.ts, 0, 0)) +>name : Symbol(name, Decl(indexTypeConstraintWithIndexedAccess1.ts, 10, 10)) +>val : Symbol(val, Decl(indexTypeConstraintWithIndexedAccess1.ts, 11, 32)) + +export type Nested = { +>Nested : Symbol(Nested, Decl(indexTypeConstraintWithIndexedAccess1.ts, 13, 34)) + + nest: { +>nest : Symbol(nest, Decl(indexTypeConstraintWithIndexedAccess1.ts, 15, 22)) + + foo: string[]; +>foo : Symbol(foo, Decl(indexTypeConstraintWithIndexedAccess1.ts, 16, 9)) + + bar: number[]; +>bar : Symbol(bar, Decl(indexTypeConstraintWithIndexedAccess1.ts, 17, 18)) + + }; +}; + +export const test = < +>test : Symbol(test, Decl(indexTypeConstraintWithIndexedAccess1.ts, 22, 12)) + + T extends keyof Nested, +>T : Symbol(T, Decl(indexTypeConstraintWithIndexedAccess1.ts, 22, 21)) +>Nested : Symbol(Nested, Decl(indexTypeConstraintWithIndexedAccess1.ts, 13, 34)) + + K extends keyof Nested[T], +>K : Symbol(K, Decl(indexTypeConstraintWithIndexedAccess1.ts, 23, 25)) +>Nested : Symbol(Nested, Decl(indexTypeConstraintWithIndexedAccess1.ts, 13, 34)) +>T : Symbol(T, Decl(indexTypeConstraintWithIndexedAccess1.ts, 22, 21)) + + V extends Nested[T][K][number], +>V : Symbol(V, Decl(indexTypeConstraintWithIndexedAccess1.ts, 24, 28)) +>Nested : Symbol(Nested, Decl(indexTypeConstraintWithIndexedAccess1.ts, 13, 34)) +>T : Symbol(T, Decl(indexTypeConstraintWithIndexedAccess1.ts, 22, 21)) +>K : Symbol(K, Decl(indexTypeConstraintWithIndexedAccess1.ts, 23, 25)) + +>( + type: T, +>type : Symbol(type, Decl(indexTypeConstraintWithIndexedAccess1.ts, 26, 2)) +>T : Symbol(T, Decl(indexTypeConstraintWithIndexedAccess1.ts, 22, 21)) + + key: K, +>key : Symbol(key, Decl(indexTypeConstraintWithIndexedAccess1.ts, 27, 10)) +>K : Symbol(K, Decl(indexTypeConstraintWithIndexedAccess1.ts, 23, 25)) + + value: V, +>value : Symbol(value, Decl(indexTypeConstraintWithIndexedAccess1.ts, 28, 9)) +>V : Symbol(V, Decl(indexTypeConstraintWithIndexedAccess1.ts, 24, 28)) + +) => {}; + +const constRoutes = { +>constRoutes : Symbol(constRoutes, Decl(indexTypeConstraintWithIndexedAccess1.ts, 32, 5)) + + users: { +>users : Symbol(users, Decl(indexTypeConstraintWithIndexedAccess1.ts, 32, 21)) + + admin: { +>admin : Symbol(admin, Decl(indexTypeConstraintWithIndexedAccess1.ts, 33, 10)) + + get: "/admin", +>get : Symbol(get, Decl(indexTypeConstraintWithIndexedAccess1.ts, 34, 12)) + + }, + }, +} as const; +>const : Symbol(const) + +type ConstRoutes = typeof constRoutes; +>ConstRoutes : Symbol(ConstRoutes, Decl(indexTypeConstraintWithIndexedAccess1.ts, 38, 11)) +>constRoutes : Symbol(constRoutes, Decl(indexTypeConstraintWithIndexedAccess1.ts, 32, 5)) + +type ConstRouteSectionName = keyof ConstRoutes; +>ConstRouteSectionName : Symbol(ConstRouteSectionName, Decl(indexTypeConstraintWithIndexedAccess1.ts, 39, 38)) +>ConstRoutes : Symbol(ConstRoutes, Decl(indexTypeConstraintWithIndexedAccess1.ts, 38, 11)) + +type ConstRouteModelName
= +>ConstRouteModelName : Symbol(ConstRouteModelName, Decl(indexTypeConstraintWithIndexedAccess1.ts, 40, 47)) +>Section : Symbol(Section, Decl(indexTypeConstraintWithIndexedAccess1.ts, 41, 25)) +>ConstRouteSectionName : Symbol(ConstRouteSectionName, Decl(indexTypeConstraintWithIndexedAccess1.ts, 39, 38)) + + keyof ConstRoutes[Section]; +>ConstRoutes : Symbol(ConstRoutes, Decl(indexTypeConstraintWithIndexedAccess1.ts, 38, 11)) +>Section : Symbol(Section, Decl(indexTypeConstraintWithIndexedAccess1.ts, 41, 25)) + +function getForConstRoute< +>getForConstRoute : Symbol(getForConstRoute, Decl(indexTypeConstraintWithIndexedAccess1.ts, 42, 29)) + + Section extends ConstRouteSectionName, +>Section : Symbol(Section, Decl(indexTypeConstraintWithIndexedAccess1.ts, 44, 26)) +>ConstRouteSectionName : Symbol(ConstRouteSectionName, Decl(indexTypeConstraintWithIndexedAccess1.ts, 39, 38)) + + Model extends ConstRouteModelName
, +>Model : Symbol(Model, Decl(indexTypeConstraintWithIndexedAccess1.ts, 45, 40)) +>ConstRouteModelName : Symbol(ConstRouteModelName, Decl(indexTypeConstraintWithIndexedAccess1.ts, 40, 47)) +>Section : Symbol(Section, Decl(indexTypeConstraintWithIndexedAccess1.ts, 44, 26)) + +>(section: Section, model: Model): string { +>section : Symbol(section, Decl(indexTypeConstraintWithIndexedAccess1.ts, 47, 2)) +>Section : Symbol(Section, Decl(indexTypeConstraintWithIndexedAccess1.ts, 44, 26)) +>model : Symbol(model, Decl(indexTypeConstraintWithIndexedAccess1.ts, 47, 19)) +>Model : Symbol(Model, Decl(indexTypeConstraintWithIndexedAccess1.ts, 45, 40)) + + return constRoutes[section][model].get; +>constRoutes[section][model].get : Symbol(get, Decl(indexTypeConstraintWithIndexedAccess1.ts, 34, 12)) +>constRoutes : Symbol(constRoutes, Decl(indexTypeConstraintWithIndexedAccess1.ts, 32, 5)) +>section : Symbol(section, Decl(indexTypeConstraintWithIndexedAccess1.ts, 47, 2)) +>model : Symbol(model, Decl(indexTypeConstraintWithIndexedAccess1.ts, 47, 19)) +>get : Symbol(get, Decl(indexTypeConstraintWithIndexedAccess1.ts, 34, 12)) +} + +interface IndexedActions { +>IndexedActions : Symbol(IndexedActions, Decl(indexTypeConstraintWithIndexedAccess1.ts, 49, 1)) + + a: { +>a : Symbol(IndexedActions.a, Decl(indexTypeConstraintWithIndexedAccess1.ts, 51, 26)) + + start: { +>start : Symbol(start, Decl(indexTypeConstraintWithIndexedAccess1.ts, 52, 6)) + + foo: string; +>foo : Symbol(foo, Decl(indexTypeConstraintWithIndexedAccess1.ts, 53, 12)) + + }; + }; +} + +type DeriveInputType< +>DeriveInputType : Symbol(DeriveInputType, Decl(indexTypeConstraintWithIndexedAccess1.ts, 57, 1)) + + N extends keyof IndexedActions, +>N : Symbol(N, Decl(indexTypeConstraintWithIndexedAccess1.ts, 59, 21)) +>IndexedActions : Symbol(IndexedActions, Decl(indexTypeConstraintWithIndexedAccess1.ts, 49, 1)) + + A extends keyof IndexedActions[N], +>A : Symbol(A, Decl(indexTypeConstraintWithIndexedAccess1.ts, 60, 33)) +>IndexedActions : Symbol(IndexedActions, Decl(indexTypeConstraintWithIndexedAccess1.ts, 49, 1)) +>N : Symbol(N, Decl(indexTypeConstraintWithIndexedAccess1.ts, 59, 21)) + +> = IndexedActions[N][A] & { namespace: N; verb: A }; +>IndexedActions : Symbol(IndexedActions, Decl(indexTypeConstraintWithIndexedAccess1.ts, 49, 1)) +>N : Symbol(N, Decl(indexTypeConstraintWithIndexedAccess1.ts, 59, 21)) +>A : Symbol(A, Decl(indexTypeConstraintWithIndexedAccess1.ts, 60, 33)) +>namespace : Symbol(namespace, Decl(indexTypeConstraintWithIndexedAccess1.ts, 62, 28)) +>N : Symbol(N, Decl(indexTypeConstraintWithIndexedAccess1.ts, 59, 21)) +>verb : Symbol(verb, Decl(indexTypeConstraintWithIndexedAccess1.ts, 62, 42)) +>A : Symbol(A, Decl(indexTypeConstraintWithIndexedAccess1.ts, 60, 33)) + +function doAction< +>doAction : Symbol(doAction, Decl(indexTypeConstraintWithIndexedAccess1.ts, 62, 53)) + + N extends keyof IndexedActions, +>N : Symbol(N, Decl(indexTypeConstraintWithIndexedAccess1.ts, 64, 18)) +>IndexedActions : Symbol(IndexedActions, Decl(indexTypeConstraintWithIndexedAccess1.ts, 49, 1)) + + A extends keyof IndexedActions[N], +>A : Symbol(A, Decl(indexTypeConstraintWithIndexedAccess1.ts, 65, 33)) +>IndexedActions : Symbol(IndexedActions, Decl(indexTypeConstraintWithIndexedAccess1.ts, 49, 1)) +>N : Symbol(N, Decl(indexTypeConstraintWithIndexedAccess1.ts, 64, 18)) + +>(action: DeriveInputType) { +>action : Symbol(action, Decl(indexTypeConstraintWithIndexedAccess1.ts, 67, 2)) +>DeriveInputType : Symbol(DeriveInputType, Decl(indexTypeConstraintWithIndexedAccess1.ts, 57, 1)) +>N : Symbol(N, Decl(indexTypeConstraintWithIndexedAccess1.ts, 64, 18)) +>A : Symbol(A, Decl(indexTypeConstraintWithIndexedAccess1.ts, 65, 33)) + + const s: string = action.verb; +>s : Symbol(s, Decl(indexTypeConstraintWithIndexedAccess1.ts, 68, 7)) +>action.verb : Symbol(verb, Decl(indexTypeConstraintWithIndexedAccess1.ts, 62, 42)) +>action : Symbol(action, Decl(indexTypeConstraintWithIndexedAccess1.ts, 67, 2)) +>verb : Symbol(verb, Decl(indexTypeConstraintWithIndexedAccess1.ts, 62, 42)) +} + diff --git a/tests/baselines/reference/indexTypeConstraintWithIndexedAccess1.types b/tests/baselines/reference/indexTypeConstraintWithIndexedAccess1.types new file mode 100644 index 0000000000000..6adaf7b2e3e7d --- /dev/null +++ b/tests/baselines/reference/indexTypeConstraintWithIndexedAccess1.types @@ -0,0 +1,196 @@ +//// [tests/cases/compiler/indexTypeConstraintWithIndexedAccess1.ts] //// + +=== indexTypeConstraintWithIndexedAccess1.ts === +// https://github.com/microsoft/TypeScript/issues/21760 + +interface IExample { + foo: { +>foo : { bar: { baz: number; }; } +> : ^^^^^^^ ^^^ + + bar: { +>bar : { baz: number; } +> : ^^^^^^^ ^^^ + + baz: number; +>baz : number +> : ^^^^^^ + } + } +} + +type F = < +>F : F +> : ^ + + name extends keyof IExample, + val extends keyof IExample[name] +>() => IExample[name][val]['baz']; + +export type Nested = { +>Nested : Nested +> : ^^^^^^ + + nest: { +>nest : { foo: string[]; bar: number[]; } +> : ^^^^^^^ ^^^^^^^ ^^^ + + foo: string[]; +>foo : string[] +> : ^^^^^^^^ + + bar: number[]; +>bar : number[] +> : ^^^^^^^^ + + }; +}; + +export const test = < +>test : (type: T, key: K, value: V) => void +> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^^^^^ +>< T extends keyof Nested, K extends keyof Nested[T], V extends Nested[T][K][number],>( type: T, key: K, value: V,) => {} : (type: T, key: K, value: V) => void +> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^^^^^ + + T extends keyof Nested, + K extends keyof Nested[T], + V extends Nested[T][K][number], +>( + type: T, +>type : T +> : ^ + + key: K, +>key : K +> : ^ + + value: V, +>value : V +> : ^ + +) => {}; + +const constRoutes = { +>constRoutes : { readonly users: { readonly admin: { readonly get: "/admin"; }; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ users: { admin: { get: "/admin", }, },} as const : { readonly users: { readonly admin: { readonly get: "/admin"; }; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ users: { admin: { get: "/admin", }, },} : { readonly users: { readonly admin: { readonly get: "/admin"; }; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + users: { +>users : { readonly admin: { readonly get: "/admin"; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ admin: { get: "/admin", }, } : { readonly admin: { readonly get: "/admin"; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + admin: { +>admin : { readonly get: "/admin"; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>{ get: "/admin", } : { readonly get: "/admin"; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + get: "/admin", +>get : "/admin" +> : ^^^^^^^^ +>"/admin" : "/admin" +> : ^^^^^^^^ + + }, + }, +} as const; +type ConstRoutes = typeof constRoutes; +>ConstRoutes : { readonly users: { readonly admin: { readonly get: "/admin"; }; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>constRoutes : { readonly users: { readonly admin: { readonly get: "/admin"; }; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +type ConstRouteSectionName = keyof ConstRoutes; +>ConstRouteSectionName : "users" +> : ^^^^^^^ + +type ConstRouteModelName
= +>ConstRouteModelName : keyof { readonly users: { readonly admin: { readonly get: "/admin"; }; }; }[Section] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + keyof ConstRoutes[Section]; + +function getForConstRoute< +>getForConstRoute :
>(section: Section, model: Model) => string +> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^ + + Section extends ConstRouteSectionName, + Model extends ConstRouteModelName
, +>(section: Section, model: Model): string { +>section : Section +> : ^^^^^^^ +>model : Model +> : ^^^^^ + + return constRoutes[section][model].get; +>constRoutes[section][model].get : "/admin" +> : ^^^^^^^^ +>constRoutes[section][model] : { readonly users: { readonly admin: { readonly get: "/admin"; }; }; }[Section][Model] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>constRoutes[section] : { readonly users: { readonly admin: { readonly get: "/admin"; }; }; }[Section] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>constRoutes : { readonly users: { readonly admin: { readonly get: "/admin"; }; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>section : Section +> : ^^^^^^^ +>model : Model +> : ^^^^^ +>get : "/admin" +> : ^^^^^^^^ +} + +interface IndexedActions { + a: { +>a : { start: { foo: string; }; } +> : ^^^^^^^^^ ^^^ + + start: { +>start : { foo: string; } +> : ^^^^^^^ ^^^ + + foo: string; +>foo : string +> : ^^^^^^ + + }; + }; +} + +type DeriveInputType< +>DeriveInputType : DeriveInputType +> : ^^^^^^^^^^^^^^^^^^^^^ + + N extends keyof IndexedActions, + A extends keyof IndexedActions[N], +> = IndexedActions[N][A] & { namespace: N; verb: A }; +>namespace : N +> : ^ +>verb : A +> : ^ + +function doAction< +>doAction : (action: DeriveInputType) => void +> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^^^^^^^^ + + N extends keyof IndexedActions, + A extends keyof IndexedActions[N], +>(action: DeriveInputType) { +>action : DeriveInputType +> : ^^^^^^^^^^^^^^^^^^^^^ + + const s: string = action.verb; +>s : string +> : ^^^^^^ +>action.verb : A +> : ^ +>action : DeriveInputType +> : ^^^^^^^^^^^^^^^^^^^^^ +>verb : A +> : ^ +} + diff --git a/tests/baselines/reference/intersectionsOfLargeUnions.types b/tests/baselines/reference/intersectionsOfLargeUnions.types index 9fd70c791c43d..8c078b4ac4443 100644 --- a/tests/baselines/reference/intersectionsOfLargeUnions.types +++ b/tests/baselines/reference/intersectionsOfLargeUnions.types @@ -2,7 +2,7 @@ === Performance Stats === Assignability cache: 1,000 -Type Count: 2,500 +Type Count: 5,000 === intersectionsOfLargeUnions.ts === // Repro from #23977 diff --git a/tests/baselines/reference/intersectionsOfLargeUnions2.types b/tests/baselines/reference/intersectionsOfLargeUnions2.types index 7216f5c7e2a10..d82d16ebcf954 100644 --- a/tests/baselines/reference/intersectionsOfLargeUnions2.types +++ b/tests/baselines/reference/intersectionsOfLargeUnions2.types @@ -2,7 +2,7 @@ === Performance Stats === Assignability cache: 1,000 -Type Count: 2,500 +Type Count: 5,000 === intersectionsOfLargeUnions2.ts === // Repro from #24233 diff --git a/tests/cases/compiler/indexTypeConstraintWithIndexedAccess1.ts b/tests/cases/compiler/indexTypeConstraintWithIndexedAccess1.ts new file mode 100644 index 0000000000000..051d1e4470cc0 --- /dev/null +++ b/tests/cases/compiler/indexTypeConstraintWithIndexedAccess1.ts @@ -0,0 +1,73 @@ +// @strict: true +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/21760 + +interface IExample { + foo: { + bar: { + baz: number; + } + } +} + +type F = < + name extends keyof IExample, + val extends keyof IExample[name] +>() => IExample[name][val]['baz']; + +export type Nested = { + nest: { + foo: string[]; + bar: number[]; + }; +}; + +export const test = < + T extends keyof Nested, + K extends keyof Nested[T], + V extends Nested[T][K][number], +>( + type: T, + key: K, + value: V, +) => {}; + +const constRoutes = { + users: { + admin: { + get: "/admin", + }, + }, +} as const; +type ConstRoutes = typeof constRoutes; +type ConstRouteSectionName = keyof ConstRoutes; +type ConstRouteModelName
= + keyof ConstRoutes[Section]; + +function getForConstRoute< + Section extends ConstRouteSectionName, + Model extends ConstRouteModelName
, +>(section: Section, model: Model): string { + return constRoutes[section][model].get; +} + +interface IndexedActions { + a: { + start: { + foo: string; + }; + }; +} + +type DeriveInputType< + N extends keyof IndexedActions, + A extends keyof IndexedActions[N], +> = IndexedActions[N][A] & { namespace: N; verb: A }; + +function doAction< + N extends keyof IndexedActions, + A extends keyof IndexedActions[N], +>(action: DeriveInputType) { + const s: string = action.verb; +}