From f6074e850dd4ffc444b1ae9d3118b6604a6100fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 2 Jan 2023 22:33:09 +0100 Subject: [PATCH 1/8] Revert "Revert "Fixed an issue with contextual type for intersection properties (#48668)" (#50279)" This reverts commit adf26ffa4b00bda9b35b048b4f1083836451463e. --- src/compiler/checker.ts | 32 +++++++- ...lTypeFunctionObjectPropertyIntersection.js | 42 ++++++++++ ...FunctionObjectPropertyIntersection.symbols | 82 +++++++++++++++++++ ...peFunctionObjectPropertyIntersection.types | 73 +++++++++++++++++ ...lTypeFunctionObjectPropertyIntersection.ts | 29 +++++++ 5 files changed, 255 insertions(+), 3 deletions(-) create mode 100644 tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.js create mode 100644 tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.symbols create mode 100644 tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.types create mode 100644 tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 54ddbb48fe11a..fe77c1891f878 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -28416,6 +28416,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getTypeOfPropertyOfContextualType(type: Type, name: __String, nameType?: Type) { return mapType(type, t => { + if (t.flags & TypeFlags.Intersection) { + const intersection = t as IntersectionType; + let newTypes = mapDefined(intersection.types, getTypeOfConcretePropertyOfContextualType); + if (newTypes.length > 0) { + return getIntersectionType(newTypes); + } + newTypes = mapDefined(intersection.types, getTypeOfApplicableIndexInfoOfContextualType); + if (newTypes.length > 0) { + return getIntersectionType(newTypes); + } + return undefined; + } + const concretePropertyType = getTypeOfConcretePropertyOfContextualType(t); + if (concretePropertyType) { + return concretePropertyType; + } + return getTypeOfApplicableIndexInfoOfContextualType(t); + }, /*noReductions*/ true); + + function getTypeOfConcretePropertyOfContextualType(t: Type) { if (isGenericMappedType(t) && !t.declaration.nameType) { const constraint = getConstraintTypeFromMappedType(t); const constraintOfConstraint = getBaseConstraintOfType(constraint) || constraint; @@ -28423,8 +28443,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isTypeAssignableTo(propertyNameType, constraintOfConstraint)) { return substituteIndexedMappedType(t, propertyNameType); } + return undefined; } - else if (t.flags & TypeFlags.StructuredType) { + if (t.flags & TypeFlags.StructuredType) { const prop = getPropertyOfType(t, name); if (prop) { return isCircularMappedProperty(prop) ? undefined : getTypeOfSymbol(prop); @@ -28435,10 +28456,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return restType; } } - return findApplicableIndexInfo(getIndexInfosOfStructuredType(t), nameType || getStringLiteralType(unescapeLeadingUnderscores(name)))?.type; } return undefined; - }, /*noReductions*/ true); + } + function getTypeOfApplicableIndexInfoOfContextualType(t: Type) { + if (!(t.flags & TypeFlags.StructuredType)) { + return undefined; + } + return findApplicableIndexInfo(getIndexInfosOfStructuredType(t), nameType || getStringLiteralType(unescapeLeadingUnderscores(name)))?.type; + } } // In an object literal contextually typed by a type T, the contextual type of a property assignment is the type of diff --git a/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.js b/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.js new file mode 100644 index 0000000000000..f1dab3794105a --- /dev/null +++ b/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.js @@ -0,0 +1,42 @@ +//// [contextualTypeFunctionObjectPropertyIntersection.ts] +type Action = (ev: TEvent) => void; + +interface MachineConfig { + schema: { + events: TEvent; + }; + on?: { + [K in TEvent["type"]]?: Action; + } & { + "*"?: Action; + }; +} + +declare function createMachine( + config: MachineConfig +): void; + +createMachine({ + schema: { + events: {} as { type: "FOO" } | { type: "BAR" }, + }, + on: { + FOO: (ev) => { + ev.type; // should be 'FOO' + }, + }, +}); + + +//// [contextualTypeFunctionObjectPropertyIntersection.js] +"use strict"; +createMachine({ + schema: { + events: {}, + }, + on: { + FOO: function (ev) { + ev.type; // should be 'FOO' + }, + }, +}); diff --git a/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.symbols b/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.symbols new file mode 100644 index 0000000000000..4690985350a17 --- /dev/null +++ b/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.symbols @@ -0,0 +1,82 @@ +=== tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts === +type Action = (ev: TEvent) => void; +>Action : Symbol(Action, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 0, 0)) +>TEvent : Symbol(TEvent, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 0, 12)) +>type : Symbol(type, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 0, 28)) +>ev : Symbol(ev, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 0, 48)) +>TEvent : Symbol(TEvent, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 0, 12)) + +interface MachineConfig { +>MachineConfig : Symbol(MachineConfig, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 0, 68)) +>TEvent : Symbol(TEvent, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 2, 24)) +>type : Symbol(type, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 2, 40)) + + schema: { +>schema : Symbol(MachineConfig.schema, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 2, 58)) + + events: TEvent; +>events : Symbol(events, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 3, 11)) +>TEvent : Symbol(TEvent, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 2, 24)) + + }; + on?: { +>on : Symbol(MachineConfig.on, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 5, 4)) + + [K in TEvent["type"]]?: Action; +>K : Symbol(K, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 7, 5)) +>TEvent : Symbol(TEvent, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 2, 24)) +>Action : Symbol(Action, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 0, 0)) +>TEvent : Symbol(TEvent, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 2, 24)) +>type : Symbol(type, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 7, 51)) +>K : Symbol(K, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 7, 5)) +>TEvent : Symbol(TEvent, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 2, 24)) + + } & { + "*"?: Action; +>"*" : Symbol("*", Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 8, 7)) +>Action : Symbol(Action, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 0, 0)) +>TEvent : Symbol(TEvent, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 2, 24)) + + }; +} + +declare function createMachine( +>createMachine : Symbol(createMachine, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 11, 1)) +>TEvent : Symbol(TEvent, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 13, 31)) +>type : Symbol(type, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 13, 47)) + + config: MachineConfig +>config : Symbol(config, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 13, 64)) +>MachineConfig : Symbol(MachineConfig, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 0, 68)) +>TEvent : Symbol(TEvent, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 13, 31)) + +): void; + +createMachine({ +>createMachine : Symbol(createMachine, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 11, 1)) + + schema: { +>schema : Symbol(schema, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 17, 15)) + + events: {} as { type: "FOO" } | { type: "BAR" }, +>events : Symbol(events, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 18, 11)) +>type : Symbol(type, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 19, 19)) +>type : Symbol(type, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 19, 37)) + + }, + on: { +>on : Symbol(on, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 20, 4)) + + FOO: (ev) => { +>FOO : Symbol(FOO, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 21, 7)) +>ev : Symbol(ev, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 22, 10)) + + ev.type; // should be 'FOO' +>ev.type : Symbol(type, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 19, 19)) +>ev : Symbol(ev, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 22, 10)) +>type : Symbol(type, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 19, 19)) + + }, + }, +}); + diff --git a/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.types b/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.types new file mode 100644 index 0000000000000..30ba52626faa5 --- /dev/null +++ b/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.types @@ -0,0 +1,73 @@ +=== tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts === +type Action = (ev: TEvent) => void; +>Action : Action +>type : string +>ev : TEvent + +interface MachineConfig { +>type : string + + schema: { +>schema : { events: TEvent; } + + events: TEvent; +>events : TEvent + + }; + on?: { +>on : ({ [K in TEvent["type"]]?: Action | undefined; } & { "*"?: Action | undefined; }) | undefined + + [K in TEvent["type"]]?: Action; +>type : K + + } & { + "*"?: Action; +>"*" : Action | undefined + + }; +} + +declare function createMachine( +>createMachine : (config: MachineConfig) => void +>type : string + + config: MachineConfig +>config : MachineConfig + +): void; + +createMachine({ +>createMachine({ schema: { events: {} as { type: "FOO" } | { type: "BAR" }, }, on: { FOO: (ev) => { ev.type; // should be 'FOO' }, },}) : void +>createMachine : (config: MachineConfig) => void +>{ schema: { events: {} as { type: "FOO" } | { type: "BAR" }, }, on: { FOO: (ev) => { ev.type; // should be 'FOO' }, },} : { schema: { events: { type: "FOO"; } | { type: "BAR"; }; }; on: { FOO: (ev: { type: "FOO"; }) => void; }; } + + schema: { +>schema : { events: { type: "FOO"; } | { type: "BAR"; }; } +>{ events: {} as { type: "FOO" } | { type: "BAR" }, } : { events: { type: "FOO"; } | { type: "BAR"; }; } + + events: {} as { type: "FOO" } | { type: "BAR" }, +>events : { type: "FOO"; } | { type: "BAR"; } +>{} as { type: "FOO" } | { type: "BAR" } : { type: "FOO"; } | { type: "BAR"; } +>{} : {} +>type : "FOO" +>type : "BAR" + + }, + on: { +>on : { FOO: (ev: { type: "FOO"; }) => void; } +>{ FOO: (ev) => { ev.type; // should be 'FOO' }, } : { FOO: (ev: { type: "FOO"; }) => void; } + + FOO: (ev) => { +>FOO : (ev: { type: "FOO"; }) => void +>(ev) => { ev.type; // should be 'FOO' } : (ev: { type: "FOO"; }) => void +>ev : { type: "FOO"; } + + ev.type; // should be 'FOO' +>ev.type : "FOO" +>ev : { type: "FOO"; } +>type : "FOO" + + }, + }, +}); + diff --git a/tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts b/tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts new file mode 100644 index 0000000000000..2d7e00f32f65e --- /dev/null +++ b/tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts @@ -0,0 +1,29 @@ +// @strict: true + +type Action = (ev: TEvent) => void; + +interface MachineConfig { + schema: { + events: TEvent; + }; + on?: { + [K in TEvent["type"]]?: Action; + } & { + "*"?: Action; + }; +} + +declare function createMachine( + config: MachineConfig +): void; + +createMachine({ + schema: { + events: {} as { type: "FOO" } | { type: "BAR" }, + }, + on: { + FOO: (ev) => { + ev.type; // should be 'FOO' + }, + }, +}); From 5b9a5ddf78698b24f2c405cf00f2c3790248f7da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 2 Jan 2023 22:47:52 +0100 Subject: [PATCH 2/8] Add failing test cases related to RTK --- ...ctionObjectPropertyIntersection.errors.txt | 99 ++++++++ ...lTypeFunctionObjectPropertyIntersection.js | 42 ---- ...FunctionObjectPropertyIntersection.symbols | 234 +++++++++++++++--- ...peFunctionObjectPropertyIntersection.types | 136 ++++++++++ ...lTypeFunctionObjectPropertyIntersection.ts | 60 +++++ 5 files changed, 493 insertions(+), 78 deletions(-) create mode 100644 tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.errors.txt delete mode 100644 tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.js diff --git a/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.errors.txt b/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.errors.txt new file mode 100644 index 0000000000000..6c3b8432ab05b --- /dev/null +++ b/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.errors.txt @@ -0,0 +1,99 @@ +tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts(40,5): error TS7006: Parameter 'a' implicitly has an 'any' type. +tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts(49,8): error TS7006: Parameter 's' implicitly has an 'any' type. +tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts(84,25): error TS7006: Parameter 'state' implicitly has an 'any' type. + + +==== tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts (3 errors) ==== + // repro from #48812 + + type Action = (ev: TEvent) => void; + + interface MachineConfig { + schema: { + events: TEvent; + }; + on?: { + [K in TEvent["type"]]?: Action; + } & { + "*"?: Action; + }; + } + + declare function createMachine( + config: MachineConfig + ): void; + + createMachine({ + schema: { + events: {} as { type: "FOO" } | { type: "BAR" }, + }, + on: { + FOO: (ev) => { + ev.type; // should be 'FOO' + }, + }, + }); + + // repro from #49307#issuecomment-1143103607 + + declare function createSlice( + reducers: { [K: string]: (state: string) => void } & { + [K in keyof T]: object; + } + ): void; + + createSlice({ + f(a) {}, // implicit any, index signature should not be used here + ~ +!!! error TS7006: Parameter 'a' implicitly has an 'any' type. + }); + + // repro from #49307#issuecomment-1196014488 + + type Validate = T & { [K in keyof T]: object } + declare function f any>>(s: S, x: Validate): void; + + f(0, { + foo: s => s + 1, + ~ +!!! error TS7006: Parameter 's' implicitly has an 'any' type. + }) + + // repro from 49307#issuecomment-1195858950 + + type SliceCaseReducers = { + [K: string]: (state: State) => State | void; + }; + + type ValidateSliceCaseReducers> = ACR & { + [T in keyof ACR]: ACR[T] extends { + reducer(s: S, action?: infer A): any; + } + ? { + prepare(...a: never[]): Omit; + } + : {}; + }; + + declare function createSlice< + State, + CaseReducers extends SliceCaseReducers + >(options: { + initialState: State | (() => State); + reducers: ValidateSliceCaseReducers; + }): void; + + export const clientSlice = createSlice({ + initialState: { + username: "", + isLoggedIn: false, + userId: "", + avatar: "", + }, + reducers: { + onClientUserChanged(state) {}, + ~~~~~ +!!! error TS7006: Parameter 'state' implicitly has an 'any' type. + }, + }); + \ No newline at end of file diff --git a/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.js b/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.js deleted file mode 100644 index f1dab3794105a..0000000000000 --- a/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.js +++ /dev/null @@ -1,42 +0,0 @@ -//// [contextualTypeFunctionObjectPropertyIntersection.ts] -type Action = (ev: TEvent) => void; - -interface MachineConfig { - schema: { - events: TEvent; - }; - on?: { - [K in TEvent["type"]]?: Action; - } & { - "*"?: Action; - }; -} - -declare function createMachine( - config: MachineConfig -): void; - -createMachine({ - schema: { - events: {} as { type: "FOO" } | { type: "BAR" }, - }, - on: { - FOO: (ev) => { - ev.type; // should be 'FOO' - }, - }, -}); - - -//// [contextualTypeFunctionObjectPropertyIntersection.js] -"use strict"; -createMachine({ - schema: { - events: {}, - }, - on: { - FOO: function (ev) { - ev.type; // should be 'FOO' - }, - }, -}); diff --git a/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.symbols b/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.symbols index 4690985350a17..c7313ce595796 100644 --- a/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.symbols +++ b/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.symbols @@ -1,82 +1,244 @@ === tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts === +// repro from #48812 + type Action = (ev: TEvent) => void; >Action : Symbol(Action, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 0, 0)) ->TEvent : Symbol(TEvent, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 0, 12)) ->type : Symbol(type, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 0, 28)) ->ev : Symbol(ev, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 0, 48)) ->TEvent : Symbol(TEvent, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 0, 12)) +>TEvent : Symbol(TEvent, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 2, 12)) +>type : Symbol(type, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 2, 28)) +>ev : Symbol(ev, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 2, 48)) +>TEvent : Symbol(TEvent, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 2, 12)) interface MachineConfig { ->MachineConfig : Symbol(MachineConfig, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 0, 68)) ->TEvent : Symbol(TEvent, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 2, 24)) ->type : Symbol(type, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 2, 40)) +>MachineConfig : Symbol(MachineConfig, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 2, 68)) +>TEvent : Symbol(TEvent, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 4, 24)) +>type : Symbol(type, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 4, 40)) schema: { ->schema : Symbol(MachineConfig.schema, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 2, 58)) +>schema : Symbol(MachineConfig.schema, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 4, 58)) events: TEvent; ->events : Symbol(events, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 3, 11)) ->TEvent : Symbol(TEvent, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 2, 24)) +>events : Symbol(events, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 5, 11)) +>TEvent : Symbol(TEvent, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 4, 24)) }; on?: { ->on : Symbol(MachineConfig.on, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 5, 4)) +>on : Symbol(MachineConfig.on, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 7, 4)) [K in TEvent["type"]]?: Action; ->K : Symbol(K, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 7, 5)) ->TEvent : Symbol(TEvent, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 2, 24)) +>K : Symbol(K, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 9, 5)) +>TEvent : Symbol(TEvent, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 4, 24)) >Action : Symbol(Action, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 0, 0)) ->TEvent : Symbol(TEvent, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 2, 24)) ->type : Symbol(type, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 7, 51)) ->K : Symbol(K, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 7, 5)) ->TEvent : Symbol(TEvent, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 2, 24)) +>TEvent : Symbol(TEvent, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 4, 24)) +>type : Symbol(type, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 9, 51)) +>K : Symbol(K, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 9, 5)) +>TEvent : Symbol(TEvent, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 4, 24)) } & { "*"?: Action; ->"*" : Symbol("*", Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 8, 7)) +>"*" : Symbol("*", Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 10, 7)) >Action : Symbol(Action, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 0, 0)) ->TEvent : Symbol(TEvent, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 2, 24)) +>TEvent : Symbol(TEvent, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 4, 24)) }; } declare function createMachine( ->createMachine : Symbol(createMachine, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 11, 1)) ->TEvent : Symbol(TEvent, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 13, 31)) ->type : Symbol(type, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 13, 47)) +>createMachine : Symbol(createMachine, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 13, 1)) +>TEvent : Symbol(TEvent, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 15, 31)) +>type : Symbol(type, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 15, 47)) config: MachineConfig ->config : Symbol(config, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 13, 64)) ->MachineConfig : Symbol(MachineConfig, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 0, 68)) ->TEvent : Symbol(TEvent, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 13, 31)) +>config : Symbol(config, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 15, 64)) +>MachineConfig : Symbol(MachineConfig, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 2, 68)) +>TEvent : Symbol(TEvent, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 15, 31)) ): void; createMachine({ ->createMachine : Symbol(createMachine, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 11, 1)) +>createMachine : Symbol(createMachine, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 13, 1)) schema: { ->schema : Symbol(schema, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 17, 15)) +>schema : Symbol(schema, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 19, 15)) events: {} as { type: "FOO" } | { type: "BAR" }, ->events : Symbol(events, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 18, 11)) ->type : Symbol(type, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 19, 19)) ->type : Symbol(type, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 19, 37)) +>events : Symbol(events, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 20, 11)) +>type : Symbol(type, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 21, 19)) +>type : Symbol(type, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 21, 37)) }, on: { ->on : Symbol(on, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 20, 4)) +>on : Symbol(on, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 22, 4)) FOO: (ev) => { ->FOO : Symbol(FOO, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 21, 7)) ->ev : Symbol(ev, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 22, 10)) +>FOO : Symbol(FOO, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 23, 7)) +>ev : Symbol(ev, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 24, 10)) ev.type; // should be 'FOO' ->ev.type : Symbol(type, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 19, 19)) ->ev : Symbol(ev, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 22, 10)) ->type : Symbol(type, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 19, 19)) +>ev.type : Symbol(type, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 21, 19)) +>ev : Symbol(ev, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 24, 10)) +>type : Symbol(type, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 21, 19)) }, }, }); +// repro from #49307#issuecomment-1143103607 + +declare function createSlice( +>createSlice : Symbol(createSlice, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 28, 3), Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 65, 2)) +>T : Symbol(T, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 32, 29)) + + reducers: { [K: string]: (state: string) => void } & { +>reducers : Symbol(reducers, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 32, 32)) +>K : Symbol(K, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 33, 15)) +>state : Symbol(state, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 33, 28)) + + [K in keyof T]: object; +>K : Symbol(K, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 34, 5)) +>T : Symbol(T, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 32, 29)) + } +): void; + +createSlice({ +>createSlice : Symbol(createSlice, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 28, 3), Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 65, 2)) + + f(a) {}, // implicit any, index signature should not be used here +>f : Symbol(f, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 38, 13)) +>a : Symbol(a, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 39, 4)) + +}); + +// repro from #49307#issuecomment-1196014488 + +type Validate = T & { [K in keyof T]: object } +>Validate : Symbol(Validate, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 40, 3)) +>T : Symbol(T, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 44, 14)) +>T : Symbol(T, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 44, 14)) +>K : Symbol(K, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 44, 26)) +>T : Symbol(T, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 44, 14)) + +declare function f any>>(s: S, x: Validate): void; +>f : Symbol(f, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 44, 49)) +>S : Symbol(S, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 45, 19)) +>T : Symbol(T, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 45, 21)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>state : Symbol(state, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 45, 48)) +>S : Symbol(S, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 45, 19)) +>s : Symbol(s, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 45, 67)) +>S : Symbol(S, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 45, 19)) +>x : Symbol(x, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 45, 72)) +>Validate : Symbol(Validate, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 40, 3)) +>T : Symbol(T, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 45, 21)) + +f(0, { +>f : Symbol(f, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 44, 49)) + + foo: s => s + 1, +>foo : Symbol(foo, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 47, 6)) +>s : Symbol(s, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 48, 6)) +>s : Symbol(s, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 48, 6)) + +}) + +// repro from 49307#issuecomment-1195858950 + +type SliceCaseReducers = { +>SliceCaseReducers : Symbol(SliceCaseReducers, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 49, 2)) +>State : Symbol(State, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 53, 23)) + + [K: string]: (state: State) => State | void; +>K : Symbol(K, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 54, 3)) +>state : Symbol(state, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 54, 16)) +>State : Symbol(State, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 53, 23)) +>State : Symbol(State, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 53, 23)) + +}; + +type ValidateSliceCaseReducers> = ACR & { +>ValidateSliceCaseReducers : Symbol(ValidateSliceCaseReducers, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 55, 2)) +>S : Symbol(S, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 57, 31)) +>ACR : Symbol(ACR, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 57, 33)) +>SliceCaseReducers : Symbol(SliceCaseReducers, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 49, 2)) +>S : Symbol(S, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 57, 31)) +>ACR : Symbol(ACR, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 57, 33)) + + [T in keyof ACR]: ACR[T] extends { +>T : Symbol(T, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 58, 3)) +>ACR : Symbol(ACR, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 57, 33)) +>ACR : Symbol(ACR, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 57, 33)) +>T : Symbol(T, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 58, 3)) + + reducer(s: S, action?: infer A): any; +>reducer : Symbol(reducer, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 58, 36)) +>s : Symbol(s, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 59, 12)) +>S : Symbol(S, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 57, 31)) +>action : Symbol(action, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 59, 17)) +>A : Symbol(A, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 59, 32)) + } + ? { + prepare(...a: never[]): Omit; +>prepare : Symbol(prepare, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 61, 7)) +>a : Symbol(a, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 62, 16)) +>Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --)) +>A : Symbol(A, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 59, 32)) + } + : {}; +}; + +declare function createSlice< +>createSlice : Symbol(createSlice, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 28, 3), Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 65, 2)) + + State, +>State : Symbol(State, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 67, 29)) + + CaseReducers extends SliceCaseReducers +>CaseReducers : Symbol(CaseReducers, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 68, 8)) +>SliceCaseReducers : Symbol(SliceCaseReducers, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 49, 2)) +>State : Symbol(State, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 67, 29)) + +>(options: { +>options : Symbol(options, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 70, 2)) + + initialState: State | (() => State); +>initialState : Symbol(initialState, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 70, 12)) +>State : Symbol(State, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 67, 29)) +>State : Symbol(State, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 67, 29)) + + reducers: ValidateSliceCaseReducers; +>reducers : Symbol(reducers, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 71, 38)) +>ValidateSliceCaseReducers : Symbol(ValidateSliceCaseReducers, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 55, 2)) +>State : Symbol(State, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 67, 29)) +>CaseReducers : Symbol(CaseReducers, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 68, 8)) + +}): void; + +export const clientSlice = createSlice({ +>clientSlice : Symbol(clientSlice, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 75, 12)) +>createSlice : Symbol(createSlice, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 28, 3), Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 65, 2)) + + initialState: { +>initialState : Symbol(initialState, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 75, 40)) + + username: "", +>username : Symbol(username, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 76, 17)) + + isLoggedIn: false, +>isLoggedIn : Symbol(isLoggedIn, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 77, 17)) + + userId: "", +>userId : Symbol(userId, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 78, 22)) + + avatar: "", +>avatar : Symbol(avatar, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 79, 15)) + + }, + reducers: { +>reducers : Symbol(reducers, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 81, 4)) + + onClientUserChanged(state) {}, +>onClientUserChanged : Symbol(onClientUserChanged, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 82, 13)) +>state : Symbol(state, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 83, 24)) + + }, +}); + diff --git a/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.types b/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.types index 30ba52626faa5..d263c7a92cf1c 100644 --- a/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.types +++ b/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.types @@ -1,4 +1,6 @@ === tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts === +// repro from #48812 + type Action = (ev: TEvent) => void; >Action : Action >type : string @@ -71,3 +73,137 @@ createMachine({ }, }); +// repro from #49307#issuecomment-1143103607 + +declare function createSlice( +>createSlice : { (reducers: { [K: string]: (state: string) => void; } & { [K in keyof T]: object; }): void; >(options: { initialState: State | (() => State); reducers: ValidateSliceCaseReducers; }): void; } + + reducers: { [K: string]: (state: string) => void } & { +>reducers : { [K: string]: (state: string) => void; } & { [K in keyof T]: object; } +>K : string +>state : string + + [K in keyof T]: object; + } +): void; + +createSlice({ +>createSlice({ f(a) {}, // implicit any, index signature should not be used here}) : void +>createSlice : { (reducers: { [K: string]: (state: string) => void; } & { [K in keyof T]: object; }): void; >(options: { initialState: State | (() => State); reducers: ValidateSliceCaseReducers; }): void; } +>{ f(a) {}, // implicit any, index signature should not be used here} : { f(a: any): void; } + + f(a) {}, // implicit any, index signature should not be used here +>f : (a: any) => void +>a : any + +}); + +// repro from #49307#issuecomment-1196014488 + +type Validate = T & { [K in keyof T]: object } +>Validate : Validate + +declare function f any>>(s: S, x: Validate): void; +>f : any>>(s: S, x: Validate) => void +>state : S +>s : S +>x : Validate + +f(0, { +>f(0, { foo: s => s + 1,}) : void +>f : any>>(s: S, x: Validate) => void +>0 : 0 +>{ foo: s => s + 1,} : { foo: (s: any) => any; } + + foo: s => s + 1, +>foo : (s: any) => any +>s => s + 1 : (s: any) => any +>s : any +>s + 1 : any +>s : any +>1 : 1 + +}) + +// repro from 49307#issuecomment-1195858950 + +type SliceCaseReducers = { +>SliceCaseReducers : SliceCaseReducers + + [K: string]: (state: State) => State | void; +>K : string +>state : State + +}; + +type ValidateSliceCaseReducers> = ACR & { +>ValidateSliceCaseReducers : ValidateSliceCaseReducers + + [T in keyof ACR]: ACR[T] extends { + reducer(s: S, action?: infer A): any; +>reducer : (s: S, action?: infer A) => any +>s : S +>action : A | undefined + } + ? { + prepare(...a: never[]): Omit; +>prepare : (...a: never[]) => Omit +>a : never[] + } + : {}; +}; + +declare function createSlice< +>createSlice : { (reducers: { [K: string]: (state: string) => void; } & { [K in keyof T]: object; }): void; >(options: { initialState: State | (() => State); reducers: ValidateSliceCaseReducers;}): void; } + + State, + CaseReducers extends SliceCaseReducers +>(options: { +>options : { initialState: State | (() => State); reducers: ValidateSliceCaseReducers; } + + initialState: State | (() => State); +>initialState : State | (() => State) + + reducers: ValidateSliceCaseReducers; +>reducers : ValidateSliceCaseReducers + +}): void; + +export const clientSlice = createSlice({ +>clientSlice : void +>createSlice({ initialState: { username: "", isLoggedIn: false, userId: "", avatar: "", }, reducers: { onClientUserChanged(state) {}, },}) : void +>createSlice : { (reducers: { [K: string]: (state: string) => void; } & { [K in keyof T]: object; }): void; >(options: { initialState: State | (() => State); reducers: ValidateSliceCaseReducers; }): void; } +>{ initialState: { username: "", isLoggedIn: false, userId: "", avatar: "", }, reducers: { onClientUserChanged(state) {}, },} : { initialState: { username: string; isLoggedIn: false; userId: string; avatar: string; }; reducers: { onClientUserChanged(state: any): void; }; } + + initialState: { +>initialState : { username: string; isLoggedIn: false; userId: string; avatar: string; } +>{ username: "", isLoggedIn: false, userId: "", avatar: "", } : { username: string; isLoggedIn: false; userId: string; avatar: string; } + + username: "", +>username : string +>"" : "" + + isLoggedIn: false, +>isLoggedIn : false +>false : false + + userId: "", +>userId : string +>"" : "" + + avatar: "", +>avatar : string +>"" : "" + + }, + reducers: { +>reducers : { onClientUserChanged(state: any): void; } +>{ onClientUserChanged(state) {}, } : { onClientUserChanged(state: any): void; } + + onClientUserChanged(state) {}, +>onClientUserChanged : (state: any) => void +>state : any + + }, +}); + diff --git a/tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts b/tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts index 2d7e00f32f65e..f3d13812f4cfa 100644 --- a/tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts +++ b/tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts @@ -1,4 +1,7 @@ // @strict: true +// @noEmit: true + +// repro from #48812 type Action = (ev: TEvent) => void; @@ -27,3 +30,60 @@ createMachine({ }, }, }); + +// repro from #49307#issuecomment-1143103607 + +declare function createSlice( + reducers: { [K: string]: (state: string) => void } & { + [K in keyof T]: object; + } +): void; + +createSlice({ + f(a) {}, // implicit any, index signature should not be used here +}); + +// repro from #49307#issuecomment-1196014488 + +type Validate = T & { [K in keyof T]: object } +declare function f any>>(s: S, x: Validate): void; + +f(0, { + foo: s => s + 1, +}) + +// repro from 49307#issuecomment-1195858950 + +type SliceCaseReducers = { + [K: string]: (state: State) => State | void; +}; + +type ValidateSliceCaseReducers> = ACR & { + [T in keyof ACR]: ACR[T] extends { + reducer(s: S, action?: infer A): any; + } + ? { + prepare(...a: never[]): Omit; + } + : {}; +}; + +declare function createSlice< + State, + CaseReducers extends SliceCaseReducers +>(options: { + initialState: State | (() => State); + reducers: ValidateSliceCaseReducers; +}): void; + +export const clientSlice = createSlice({ + initialState: { + username: "", + isLoggedIn: false, + userId: "", + avatar: "", + }, + reducers: { + onClientUserChanged(state) {}, + }, +}); From bafe4fbe48eeced8c4e13f8ef7fa483772e0e331 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 4 Jan 2023 07:15:50 +0100 Subject: [PATCH 3/8] Treat properties of non-generic mapped types as concrete-like --- src/compiler/checker.ts | 9 +- ...ctionObjectPropertyIntersection.errors.txt | 12 +-- ...FunctionObjectPropertyIntersection.symbols | 92 +++++++++---------- ...peFunctionObjectPropertyIntersection.types | 29 +++--- ...lTypeFunctionObjectPropertyIntersection.ts | 4 +- 5 files changed, 65 insertions(+), 81 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index fe77c1891f878..014676cdfe9db 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -28418,7 +28418,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return mapType(type, t => { if (t.flags & TypeFlags.Intersection) { const intersection = t as IntersectionType; - let newTypes = mapDefined(intersection.types, getTypeOfConcretePropertyOfContextualType); + let newTypes = mapDefined(intersection.types, getTypeOfConcreteLikePropertyOfContextualType); if (newTypes.length > 0) { return getIntersectionType(newTypes); } @@ -28428,14 +28428,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } return undefined; } - const concretePropertyType = getTypeOfConcretePropertyOfContextualType(t); + const concretePropertyType = getTypeOfConcreteLikePropertyOfContextualType(t); if (concretePropertyType) { return concretePropertyType; } return getTypeOfApplicableIndexInfoOfContextualType(t); }, /*noReductions*/ true); - function getTypeOfConcretePropertyOfContextualType(t: Type) { + function getTypeOfConcreteLikePropertyOfContextualType(t: Type) { if (isGenericMappedType(t) && !t.declaration.nameType) { const constraint = getConstraintTypeFromMappedType(t); const constraintOfConstraint = getBaseConstraintOfType(constraint) || constraint; @@ -28456,6 +28456,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return restType; } } + if (getObjectFlags(t) & ObjectFlags.Mapped) { + return getTypeOfApplicableIndexInfoOfContextualType(t); + } } return undefined; } diff --git a/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.errors.txt b/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.errors.txt index 6c3b8432ab05b..5c317f2374a20 100644 --- a/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.errors.txt +++ b/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.errors.txt @@ -1,9 +1,7 @@ tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts(40,5): error TS7006: Parameter 'a' implicitly has an 'any' type. -tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts(49,8): error TS7006: Parameter 's' implicitly has an 'any' type. -tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts(84,25): error TS7006: Parameter 'state' implicitly has an 'any' type. -==== tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts (3 errors) ==== +==== tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts (1 errors) ==== // repro from #48812 type Action = (ev: TEvent) => void; @@ -55,15 +53,11 @@ tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts(84,25): f(0, { foo: s => s + 1, - ~ -!!! error TS7006: Parameter 's' implicitly has an 'any' type. }) // repro from 49307#issuecomment-1195858950 - type SliceCaseReducers = { - [K: string]: (state: State) => State | void; - }; + type SliceCaseReducers = Record State | void>; type ValidateSliceCaseReducers> = ACR & { [T in keyof ACR]: ACR[T] extends { @@ -92,8 +86,6 @@ tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts(84,25): }, reducers: { onClientUserChanged(state) {}, - ~~~~~ -!!! error TS7006: Parameter 'state' implicitly has an 'any' type. }, }); \ No newline at end of file diff --git a/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.symbols b/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.symbols index c7313ce595796..1593f5dbbeb14 100644 --- a/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.symbols +++ b/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.symbols @@ -85,7 +85,7 @@ createMachine({ // repro from #49307#issuecomment-1143103607 declare function createSlice( ->createSlice : Symbol(createSlice, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 28, 3), Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 65, 2)) +>createSlice : Symbol(createSlice, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 28, 3), Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 63, 2)) >T : Symbol(T, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 32, 29)) reducers: { [K: string]: (state: string) => void } & { @@ -100,7 +100,7 @@ declare function createSlice( ): void; createSlice({ ->createSlice : Symbol(createSlice, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 28, 3), Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 65, 2)) +>createSlice : Symbol(createSlice, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 28, 3), Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 63, 2)) f(a) {}, // implicit any, index signature should not be used here >f : Symbol(f, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 38, 13)) @@ -142,102 +142,98 @@ f(0, { // repro from 49307#issuecomment-1195858950 -type SliceCaseReducers = { +type SliceCaseReducers = Record State | void>; >SliceCaseReducers : Symbol(SliceCaseReducers, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 49, 2)) >State : Symbol(State, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 53, 23)) - - [K: string]: (state: State) => State | void; ->K : Symbol(K, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 54, 3)) ->state : Symbol(state, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 54, 16)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>state : Symbol(state, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 53, 48)) >State : Symbol(State, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 53, 23)) >State : Symbol(State, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 53, 23)) -}; - type ValidateSliceCaseReducers> = ACR & { ->ValidateSliceCaseReducers : Symbol(ValidateSliceCaseReducers, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 55, 2)) ->S : Symbol(S, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 57, 31)) ->ACR : Symbol(ACR, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 57, 33)) +>ValidateSliceCaseReducers : Symbol(ValidateSliceCaseReducers, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 53, 79)) +>S : Symbol(S, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 55, 31)) +>ACR : Symbol(ACR, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 55, 33)) >SliceCaseReducers : Symbol(SliceCaseReducers, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 49, 2)) ->S : Symbol(S, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 57, 31)) ->ACR : Symbol(ACR, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 57, 33)) +>S : Symbol(S, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 55, 31)) +>ACR : Symbol(ACR, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 55, 33)) [T in keyof ACR]: ACR[T] extends { ->T : Symbol(T, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 58, 3)) ->ACR : Symbol(ACR, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 57, 33)) ->ACR : Symbol(ACR, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 57, 33)) ->T : Symbol(T, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 58, 3)) +>T : Symbol(T, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 56, 3)) +>ACR : Symbol(ACR, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 55, 33)) +>ACR : Symbol(ACR, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 55, 33)) +>T : Symbol(T, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 56, 3)) reducer(s: S, action?: infer A): any; ->reducer : Symbol(reducer, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 58, 36)) ->s : Symbol(s, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 59, 12)) ->S : Symbol(S, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 57, 31)) ->action : Symbol(action, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 59, 17)) ->A : Symbol(A, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 59, 32)) +>reducer : Symbol(reducer, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 56, 36)) +>s : Symbol(s, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 57, 12)) +>S : Symbol(S, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 55, 31)) +>action : Symbol(action, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 57, 17)) +>A : Symbol(A, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 57, 32)) } ? { prepare(...a: never[]): Omit; ->prepare : Symbol(prepare, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 61, 7)) ->a : Symbol(a, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 62, 16)) +>prepare : Symbol(prepare, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 59, 7)) +>a : Symbol(a, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 60, 16)) >Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --)) ->A : Symbol(A, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 59, 32)) +>A : Symbol(A, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 57, 32)) } : {}; }; declare function createSlice< ->createSlice : Symbol(createSlice, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 28, 3), Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 65, 2)) +>createSlice : Symbol(createSlice, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 28, 3), Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 63, 2)) State, ->State : Symbol(State, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 67, 29)) +>State : Symbol(State, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 65, 29)) CaseReducers extends SliceCaseReducers ->CaseReducers : Symbol(CaseReducers, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 68, 8)) +>CaseReducers : Symbol(CaseReducers, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 66, 8)) >SliceCaseReducers : Symbol(SliceCaseReducers, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 49, 2)) ->State : Symbol(State, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 67, 29)) +>State : Symbol(State, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 65, 29)) >(options: { ->options : Symbol(options, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 70, 2)) +>options : Symbol(options, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 68, 2)) initialState: State | (() => State); ->initialState : Symbol(initialState, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 70, 12)) ->State : Symbol(State, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 67, 29)) ->State : Symbol(State, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 67, 29)) +>initialState : Symbol(initialState, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 68, 12)) +>State : Symbol(State, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 65, 29)) +>State : Symbol(State, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 65, 29)) reducers: ValidateSliceCaseReducers; ->reducers : Symbol(reducers, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 71, 38)) ->ValidateSliceCaseReducers : Symbol(ValidateSliceCaseReducers, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 55, 2)) ->State : Symbol(State, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 67, 29)) ->CaseReducers : Symbol(CaseReducers, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 68, 8)) +>reducers : Symbol(reducers, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 69, 38)) +>ValidateSliceCaseReducers : Symbol(ValidateSliceCaseReducers, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 53, 79)) +>State : Symbol(State, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 65, 29)) +>CaseReducers : Symbol(CaseReducers, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 66, 8)) }): void; export const clientSlice = createSlice({ ->clientSlice : Symbol(clientSlice, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 75, 12)) ->createSlice : Symbol(createSlice, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 28, 3), Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 65, 2)) +>clientSlice : Symbol(clientSlice, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 73, 12)) +>createSlice : Symbol(createSlice, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 28, 3), Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 63, 2)) initialState: { ->initialState : Symbol(initialState, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 75, 40)) +>initialState : Symbol(initialState, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 73, 40)) username: "", ->username : Symbol(username, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 76, 17)) +>username : Symbol(username, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 74, 17)) isLoggedIn: false, ->isLoggedIn : Symbol(isLoggedIn, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 77, 17)) +>isLoggedIn : Symbol(isLoggedIn, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 75, 17)) userId: "", ->userId : Symbol(userId, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 78, 22)) +>userId : Symbol(userId, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 76, 22)) avatar: "", ->avatar : Symbol(avatar, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 79, 15)) +>avatar : Symbol(avatar, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 77, 15)) }, reducers: { ->reducers : Symbol(reducers, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 81, 4)) +>reducers : Symbol(reducers, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 79, 4)) onClientUserChanged(state) {}, ->onClientUserChanged : Symbol(onClientUserChanged, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 82, 13)) ->state : Symbol(state, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 83, 24)) +>onClientUserChanged : Symbol(onClientUserChanged, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 80, 13)) +>state : Symbol(state, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 81, 24)) }, }); diff --git a/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.types b/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.types index d263c7a92cf1c..16e98a0e87f8b 100644 --- a/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.types +++ b/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.types @@ -113,29 +113,24 @@ f(0, { >f(0, { foo: s => s + 1,}) : void >f : any>>(s: S, x: Validate) => void >0 : 0 ->{ foo: s => s + 1,} : { foo: (s: any) => any; } +>{ foo: s => s + 1,} : { foo: (s: number) => number; } foo: s => s + 1, ->foo : (s: any) => any ->s => s + 1 : (s: any) => any ->s : any ->s + 1 : any ->s : any +>foo : (s: number) => number +>s => s + 1 : (s: number) => number +>s : number +>s + 1 : number +>s : number >1 : 1 }) // repro from 49307#issuecomment-1195858950 -type SliceCaseReducers = { +type SliceCaseReducers = Record State | void>; >SliceCaseReducers : SliceCaseReducers - - [K: string]: (state: State) => State | void; ->K : string >state : State -}; - type ValidateSliceCaseReducers> = ACR & { >ValidateSliceCaseReducers : ValidateSliceCaseReducers @@ -173,7 +168,7 @@ export const clientSlice = createSlice({ >clientSlice : void >createSlice({ initialState: { username: "", isLoggedIn: false, userId: "", avatar: "", }, reducers: { onClientUserChanged(state) {}, },}) : void >createSlice : { (reducers: { [K: string]: (state: string) => void; } & { [K in keyof T]: object; }): void; >(options: { initialState: State | (() => State); reducers: ValidateSliceCaseReducers; }): void; } ->{ initialState: { username: "", isLoggedIn: false, userId: "", avatar: "", }, reducers: { onClientUserChanged(state) {}, },} : { initialState: { username: string; isLoggedIn: false; userId: string; avatar: string; }; reducers: { onClientUserChanged(state: any): void; }; } +>{ initialState: { username: "", isLoggedIn: false, userId: "", avatar: "", }, reducers: { onClientUserChanged(state) {}, },} : { initialState: { username: string; isLoggedIn: false; userId: string; avatar: string; }; reducers: { onClientUserChanged(state: { username: string; isLoggedIn: boolean; userId: string; avatar: string; }): void; }; } initialState: { >initialState : { username: string; isLoggedIn: false; userId: string; avatar: string; } @@ -197,12 +192,12 @@ export const clientSlice = createSlice({ }, reducers: { ->reducers : { onClientUserChanged(state: any): void; } ->{ onClientUserChanged(state) {}, } : { onClientUserChanged(state: any): void; } +>reducers : { onClientUserChanged(state: { username: string; isLoggedIn: boolean; userId: string; avatar: string; }): void; } +>{ onClientUserChanged(state) {}, } : { onClientUserChanged(state: { username: string; isLoggedIn: boolean; userId: string; avatar: string; }): void; } onClientUserChanged(state) {}, ->onClientUserChanged : (state: any) => void ->state : any +>onClientUserChanged : (state: { username: string; isLoggedIn: boolean; userId: string; avatar: string; }) => void +>state : { username: string; isLoggedIn: boolean; userId: string; avatar: string; } }, }); diff --git a/tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts b/tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts index f3d13812f4cfa..2cbd09e7251e2 100644 --- a/tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts +++ b/tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts @@ -54,9 +54,7 @@ f(0, { // repro from 49307#issuecomment-1195858950 -type SliceCaseReducers = { - [K: string]: (state: State) => State | void; -}; +type SliceCaseReducers = Record State | void>; type ValidateSliceCaseReducers> = ACR & { [T in keyof ACR]: ACR[T] extends { From 3ab57738eb32fe8715fbbd14bccbf1e96e5ddf65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 22 May 2023 21:39:05 +0200 Subject: [PATCH 4/8] always concat indexed mapped type substitutions with either types from concrete props or from applicable index infos --- src/compiler/checker.ts | 81 ++++++++++------- ...ctionObjectPropertyIntersection.errors.txt | 91 ------------------- ...FunctionObjectPropertyIntersection.symbols | 2 +- ...peFunctionObjectPropertyIntersection.types | 10 +- ...lTypeFunctionObjectPropertyIntersection.ts | 2 +- 5 files changed, 53 insertions(+), 133 deletions(-) delete mode 100644 tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.errors.txt diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1dd558dc15125..0af6b57ace8cd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -29148,54 +29148,65 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return mapType(type, t => { if (t.flags & TypeFlags.Intersection) { const intersection = t as IntersectionType; - let newTypes = mapDefined(intersection.types, getTypeOfConcreteLikePropertyOfContextualType); - if (newTypes.length > 0) { - return getIntersectionType(newTypes); + let applicableIndexedMappedTypeSubstitions: Type[] | undefined; + let concreteProperties: Type[] | undefined; + let applicableIndexInfoCandidates: Type[] | undefined; + for (const t of intersection.types) { + if (isGenericMappedType(t) && !t.declaration.nameType) { + applicableIndexedMappedTypeSubstitions = append(applicableIndexedMappedTypeSubstitions, getTypeOfApplicableIndexedMappedTypeSubstitutionOfContextualType(t)); + continue; + } + if (!(t.flags & TypeFlags.StructuredType)) { + continue; + } + let type: Type | undefined; + if (type = getTypeOfConcretePropertyOfContextualType(t)) { + concreteProperties = append(concreteProperties, type); + continue; + } + applicableIndexInfoCandidates = append(applicableIndexInfoCandidates, t); + } + if (concreteProperties) { + return getIntersectionType(concatenate(concreteProperties, applicableIndexedMappedTypeSubstitions)); } - newTypes = mapDefined(intersection.types, getTypeOfApplicableIndexInfoOfContextualType); - if (newTypes.length > 0) { - return getIntersectionType(newTypes); + const types = concatenate(mapDefined(applicableIndexInfoCandidates, getTypeOfApplicableIndexInfoOfContextualType), applicableIndexedMappedTypeSubstitions); + if (types.length > 0) { + return getIntersectionType(types); } return undefined; } - const concretePropertyType = getTypeOfConcreteLikePropertyOfContextualType(t); - if (concretePropertyType) { - return concretePropertyType; + if (isGenericMappedType(t) && !t.declaration.nameType) { + return getTypeOfApplicableIndexedMappedTypeSubstitutionOfContextualType(t); + } + if (!(t.flags & TypeFlags.StructuredType)) { + return undefined; } - return getTypeOfApplicableIndexInfoOfContextualType(t); + return getTypeOfConcretePropertyOfContextualType(t) || getTypeOfApplicableIndexInfoOfContextualType(t); }, /*noReductions*/ true); - function getTypeOfConcreteLikePropertyOfContextualType(t: Type) { - if (isGenericMappedType(t) && !t.declaration.nameType) { - const constraint = getConstraintTypeFromMappedType(t); - const constraintOfConstraint = getBaseConstraintOfType(constraint) || constraint; - const propertyNameType = nameType || getStringLiteralType(unescapeLeadingUnderscores(name)); - if (isTypeAssignableTo(propertyNameType, constraintOfConstraint)) { - return substituteIndexedMappedType(t, propertyNameType); - } - return undefined; + function getTypeOfApplicableIndexedMappedTypeSubstitutionOfContextualType(t: MappedType) { + const constraint = getConstraintTypeFromMappedType(t); + const constraintOfConstraint = getBaseConstraintOfType(constraint) || constraint; + const propertyNameType = nameType || getStringLiteralType(unescapeLeadingUnderscores(name)); + if (isTypeAssignableTo(propertyNameType, constraintOfConstraint)) { + return substituteIndexedMappedType(t, propertyNameType); } - if (t.flags & TypeFlags.StructuredType) { - const prop = getPropertyOfType(t, name); - if (prop) { - return isCircularMappedProperty(prop) ? undefined : getTypeOfSymbol(prop); - } - if (isTupleType(t) && isNumericLiteralName(name) && +name >= 0) { - const restType = getElementTypeOfSliceOfTupleType(t, t.target.fixedLength, /*endSkipCount*/ 0, /*writing*/ false, /*noReductions*/ true); - if (restType) { - return restType; - } - } - if (getObjectFlags(t) & ObjectFlags.Mapped) { - return getTypeOfApplicableIndexInfoOfContextualType(t); + return undefined; + } + function getTypeOfConcretePropertyOfContextualType(t: Type) { + const prop = getPropertyOfType(t, name); + if (prop) { + return isCircularMappedProperty(prop) ? undefined : getTypeOfSymbol(prop); + } + if (isTupleType(t) && isNumericLiteralName(name) && +name >= 0) { + const restType = getElementTypeOfSliceOfTupleType(t, t.target.fixedLength, /*endSkipCount*/ 0, /*writing*/ false, /*noReductions*/ true); + if (restType) { + return restType; } } return undefined; } function getTypeOfApplicableIndexInfoOfContextualType(t: Type) { - if (!(t.flags & TypeFlags.StructuredType)) { - return undefined; - } return findApplicableIndexInfo(getIndexInfosOfStructuredType(t), nameType || getStringLiteralType(unescapeLeadingUnderscores(name)))?.type; } } diff --git a/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.errors.txt b/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.errors.txt deleted file mode 100644 index 5c317f2374a20..0000000000000 --- a/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.errors.txt +++ /dev/null @@ -1,91 +0,0 @@ -tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts(40,5): error TS7006: Parameter 'a' implicitly has an 'any' type. - - -==== tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts (1 errors) ==== - // repro from #48812 - - type Action = (ev: TEvent) => void; - - interface MachineConfig { - schema: { - events: TEvent; - }; - on?: { - [K in TEvent["type"]]?: Action; - } & { - "*"?: Action; - }; - } - - declare function createMachine( - config: MachineConfig - ): void; - - createMachine({ - schema: { - events: {} as { type: "FOO" } | { type: "BAR" }, - }, - on: { - FOO: (ev) => { - ev.type; // should be 'FOO' - }, - }, - }); - - // repro from #49307#issuecomment-1143103607 - - declare function createSlice( - reducers: { [K: string]: (state: string) => void } & { - [K in keyof T]: object; - } - ): void; - - createSlice({ - f(a) {}, // implicit any, index signature should not be used here - ~ -!!! error TS7006: Parameter 'a' implicitly has an 'any' type. - }); - - // repro from #49307#issuecomment-1196014488 - - type Validate = T & { [K in keyof T]: object } - declare function f any>>(s: S, x: Validate): void; - - f(0, { - foo: s => s + 1, - }) - - // repro from 49307#issuecomment-1195858950 - - type SliceCaseReducers = Record State | void>; - - type ValidateSliceCaseReducers> = ACR & { - [T in keyof ACR]: ACR[T] extends { - reducer(s: S, action?: infer A): any; - } - ? { - prepare(...a: never[]): Omit; - } - : {}; - }; - - declare function createSlice< - State, - CaseReducers extends SliceCaseReducers - >(options: { - initialState: State | (() => State); - reducers: ValidateSliceCaseReducers; - }): void; - - export const clientSlice = createSlice({ - initialState: { - username: "", - isLoggedIn: false, - userId: "", - avatar: "", - }, - reducers: { - onClientUserChanged(state) {}, - }, - }); - \ No newline at end of file diff --git a/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.symbols b/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.symbols index 1593f5dbbeb14..4cc58ac4f6b15 100644 --- a/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.symbols +++ b/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.symbols @@ -102,7 +102,7 @@ declare function createSlice( createSlice({ >createSlice : Symbol(createSlice, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 28, 3), Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 63, 2)) - f(a) {}, // implicit any, index signature should not be used here + f(a) {}, >f : Symbol(f, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 38, 13)) >a : Symbol(a, Decl(contextualTypeFunctionObjectPropertyIntersection.ts, 39, 4)) diff --git a/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.types b/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.types index 16e98a0e87f8b..bee2a4b146c8d 100644 --- a/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.types +++ b/tests/baselines/reference/contextualTypeFunctionObjectPropertyIntersection.types @@ -88,13 +88,13 @@ declare function createSlice( ): void; createSlice({ ->createSlice({ f(a) {}, // implicit any, index signature should not be used here}) : void +>createSlice({ f(a) {},}) : void >createSlice : { (reducers: { [K: string]: (state: string) => void; } & { [K in keyof T]: object; }): void; >(options: { initialState: State | (() => State); reducers: ValidateSliceCaseReducers; }): void; } ->{ f(a) {}, // implicit any, index signature should not be used here} : { f(a: any): void; } +>{ f(a) {},} : { f(a: string): void; } - f(a) {}, // implicit any, index signature should not be used here ->f : (a: any) => void ->a : any + f(a) {}, +>f : (a: string) => void +>a : string }); diff --git a/tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts b/tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts index 2cbd09e7251e2..db09170d13e95 100644 --- a/tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts +++ b/tests/cases/compiler/contextualTypeFunctionObjectPropertyIntersection.ts @@ -40,7 +40,7 @@ declare function createSlice( ): void; createSlice({ - f(a) {}, // implicit any, index signature should not be used here + f(a) {}, }); // repro from #49307#issuecomment-1196014488 From 48faaa32a667eabd52232271fdb0f285df9cd318 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Tue, 23 May 2023 00:35:36 +0200 Subject: [PATCH 5/8] tweak code --- src/compiler/checker.ts | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0af6b57ace8cd..7cfcd2b5682d4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -29146,6 +29146,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getTypeOfPropertyOfContextualType(type: Type, name: __String, nameType?: Type) { return mapType(type, t => { + if (!(t.flags & TypeFlags.StructuredType)) { + return undefined; + } if (t.flags & TypeFlags.Intersection) { const intersection = t as IntersectionType; let applicableIndexedMappedTypeSubstitions: Type[] | undefined; @@ -29156,12 +29159,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { applicableIndexedMappedTypeSubstitions = append(applicableIndexedMappedTypeSubstitions, getTypeOfApplicableIndexedMappedTypeSubstitutionOfContextualType(t)); continue; } - if (!(t.flags & TypeFlags.StructuredType)) { - continue; - } - let type: Type | undefined; - if (type = getTypeOfConcretePropertyOfContextualType(t)) { - concreteProperties = append(concreteProperties, type); + const typeOfConcreteProperty = getTypeOfConcretePropertyOfContextualType(t); + if (typeOfConcreteProperty) { + concreteProperties = append(concreteProperties, typeOfConcreteProperty); continue; } applicableIndexInfoCandidates = append(applicableIndexInfoCandidates, t); @@ -29175,13 +29175,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } return undefined; } - if (isGenericMappedType(t) && !t.declaration.nameType) { - return getTypeOfApplicableIndexedMappedTypeSubstitutionOfContextualType(t); - } - if (!(t.flags & TypeFlags.StructuredType)) { - return undefined; - } - return getTypeOfConcretePropertyOfContextualType(t) || getTypeOfApplicableIndexInfoOfContextualType(t); + return isGenericMappedType(t) && !t.declaration.nameType + ? getTypeOfApplicableIndexedMappedTypeSubstitutionOfContextualType(t) + : getTypeOfConcretePropertyOfContextualType(t) || getTypeOfApplicableIndexInfoOfContextualType(t); }, /*noReductions*/ true); function getTypeOfApplicableIndexedMappedTypeSubstitutionOfContextualType(t: MappedType) { From 937a0ea6d37fccecd267b256942cb0f36cddeb04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Tue, 23 May 2023 00:38:53 +0200 Subject: [PATCH 6/8] rename variable --- src/compiler/checker.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7cfcd2b5682d4..9386544d0bcf4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -29152,7 +29152,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (t.flags & TypeFlags.Intersection) { const intersection = t as IntersectionType; let applicableIndexedMappedTypeSubstitions: Type[] | undefined; - let concreteProperties: Type[] | undefined; + let concretePropertyTypes: Type[] | undefined; let applicableIndexInfoCandidates: Type[] | undefined; for (const t of intersection.types) { if (isGenericMappedType(t) && !t.declaration.nameType) { @@ -29161,13 +29161,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const typeOfConcreteProperty = getTypeOfConcretePropertyOfContextualType(t); if (typeOfConcreteProperty) { - concreteProperties = append(concreteProperties, typeOfConcreteProperty); + concretePropertyTypes = append(concretePropertyTypes, typeOfConcreteProperty); continue; } applicableIndexInfoCandidates = append(applicableIndexInfoCandidates, t); } - if (concreteProperties) { - return getIntersectionType(concatenate(concreteProperties, applicableIndexedMappedTypeSubstitions)); + if (concretePropertyTypes) { + return getIntersectionType(concatenate(concretePropertyTypes, applicableIndexedMappedTypeSubstitions)); } const types = concatenate(mapDefined(applicableIndexInfoCandidates, getTypeOfApplicableIndexInfoOfContextualType), applicableIndexedMappedTypeSubstitions); if (types.length > 0) { From 6d24ca825d1726d0b07d3e99e7bf0fbee394e1f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Tue, 25 Jul 2023 18:34:33 +0200 Subject: [PATCH 7/8] Add an extra test case related to JSX --- .../contextuallyTypedJsxAttribute2.symbols | 48 +++++++++++++++++++ .../contextuallyTypedJsxAttribute2.types | 44 +++++++++++++++++ .../contextuallyTypedJsxAttribute2.tsx | 20 ++++++++ 3 files changed, 112 insertions(+) create mode 100644 tests/baselines/reference/contextuallyTypedJsxAttribute2.symbols create mode 100644 tests/baselines/reference/contextuallyTypedJsxAttribute2.types create mode 100644 tests/cases/compiler/contextuallyTypedJsxAttribute2.tsx diff --git a/tests/baselines/reference/contextuallyTypedJsxAttribute2.symbols b/tests/baselines/reference/contextuallyTypedJsxAttribute2.symbols new file mode 100644 index 0000000000000..f8fb7991cb23b --- /dev/null +++ b/tests/baselines/reference/contextuallyTypedJsxAttribute2.symbols @@ -0,0 +1,48 @@ +//// [tests/cases/compiler/contextuallyTypedJsxAttribute2.tsx] //// + +=== contextuallyTypedJsxAttribute2.tsx === +/// + +import React from "react"; +>React : Symbol(React, Decl(contextuallyTypedJsxAttribute2.tsx, 2, 6)) + +import { ComponentPropsWithRef, ElementType } from "react"; +>ComponentPropsWithRef : Symbol(ComponentPropsWithRef, Decl(contextuallyTypedJsxAttribute2.tsx, 3, 8)) +>ElementType : Symbol(ElementType, Decl(contextuallyTypedJsxAttribute2.tsx, 3, 31)) + +function UnwrappedLink( +>UnwrappedLink : Symbol(UnwrappedLink, Decl(contextuallyTypedJsxAttribute2.tsx, 3, 59)) +>T : Symbol(T, Decl(contextuallyTypedJsxAttribute2.tsx, 5, 23)) +>ElementType : Symbol(ElementType, Decl(contextuallyTypedJsxAttribute2.tsx, 3, 31)) +>ElementType : Symbol(ElementType, Decl(contextuallyTypedJsxAttribute2.tsx, 3, 31)) + + props: Omit, "as"> & { +>props : Symbol(props, Decl(contextuallyTypedJsxAttribute2.tsx, 5, 60)) +>Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --)) +>ComponentPropsWithRef : Symbol(ComponentPropsWithRef, Decl(contextuallyTypedJsxAttribute2.tsx, 3, 8)) +>ElementType : Symbol(ElementType, Decl(contextuallyTypedJsxAttribute2.tsx, 3, 31)) +>T : Symbol(T, Decl(contextuallyTypedJsxAttribute2.tsx, 5, 23)) +>T : Symbol(T, Decl(contextuallyTypedJsxAttribute2.tsx, 5, 23)) + + as?: T; +>as : Symbol(as, Decl(contextuallyTypedJsxAttribute2.tsx, 6, 79)) +>T : Symbol(T, Decl(contextuallyTypedJsxAttribute2.tsx, 5, 23)) + + }, +) { + return ; +>a : Symbol(JSX.IntrinsicElements.a, Decl(react16.d.ts, 2516, 41)) +>a : Symbol(JSX.IntrinsicElements.a, Decl(react16.d.ts, 2516, 41)) +} + + {}} />; +>UnwrappedLink : Symbol(UnwrappedLink, Decl(contextuallyTypedJsxAttribute2.tsx, 3, 59)) +>onClick : Symbol(onClick, Decl(contextuallyTypedJsxAttribute2.tsx, 13, 14)) +>e : Symbol(e, Decl(contextuallyTypedJsxAttribute2.tsx, 13, 25)) + + {}} />; +>UnwrappedLink : Symbol(UnwrappedLink, Decl(contextuallyTypedJsxAttribute2.tsx, 3, 59)) +>as : Symbol(as, Decl(contextuallyTypedJsxAttribute2.tsx, 14, 14)) +>onClick : Symbol(onClick, Decl(contextuallyTypedJsxAttribute2.tsx, 14, 26)) +>e : Symbol(e, Decl(contextuallyTypedJsxAttribute2.tsx, 14, 37)) + diff --git a/tests/baselines/reference/contextuallyTypedJsxAttribute2.types b/tests/baselines/reference/contextuallyTypedJsxAttribute2.types new file mode 100644 index 0000000000000..05a6356dd284f --- /dev/null +++ b/tests/baselines/reference/contextuallyTypedJsxAttribute2.types @@ -0,0 +1,44 @@ +//// [tests/cases/compiler/contextuallyTypedJsxAttribute2.tsx] //// + +=== contextuallyTypedJsxAttribute2.tsx === +/// + +import React from "react"; +>React : typeof React + +import { ComponentPropsWithRef, ElementType } from "react"; +>ComponentPropsWithRef : any +>ElementType : any + +function UnwrappedLink( +>UnwrappedLink : (props: Omit, "as"> & { as?: T;}) => JSX.Element + + props: Omit, "as"> & { +>props : Omit, "as"> & { as?: T | undefined; } + + as?: T; +>as : T | undefined + + }, +) { + return ; +> : JSX.Element +>a : any +>a : any +} + + {}} />; +> {}} /> : JSX.Element +>UnwrappedLink : (props: Omit, "as"> & { as?: T | undefined; }) => JSX.Element +>onClick : (e: React.MouseEvent) => void +>(e) => {} : (e: React.MouseEvent) => void +>e : React.MouseEvent + + {}} />; +> {}} /> : JSX.Element +>UnwrappedLink : (props: Omit, "as"> & { as?: T | undefined; }) => JSX.Element +>as : "button" +>onClick : (e: React.MouseEvent) => void +>(e) => {} : (e: React.MouseEvent) => void +>e : React.MouseEvent + diff --git a/tests/cases/compiler/contextuallyTypedJsxAttribute2.tsx b/tests/cases/compiler/contextuallyTypedJsxAttribute2.tsx new file mode 100644 index 0000000000000..d94409f720ce0 --- /dev/null +++ b/tests/cases/compiler/contextuallyTypedJsxAttribute2.tsx @@ -0,0 +1,20 @@ +// @strict: true +// @jsx: react +// @esModuleInterop: true +// @noEmit: true + +/// + +import React from "react"; +import { ComponentPropsWithRef, ElementType } from "react"; + +function UnwrappedLink( + props: Omit, "as"> & { + as?: T; + }, +) { + return ; +} + + {}} />; + {}} />; From ea31c96a72f5c19b3d960b45dae3cdba83cbbb53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Tue, 25 Jul 2023 18:46:57 +0200 Subject: [PATCH 8/8] expand the JSX test --- .../contextuallyTypedJsxAttribute2.symbols | 49 ++++++++++++++----- .../contextuallyTypedJsxAttribute2.types | 34 ++++++++++--- .../contextuallyTypedJsxAttribute2.tsx | 12 ++++- 3 files changed, 74 insertions(+), 21 deletions(-) diff --git a/tests/baselines/reference/contextuallyTypedJsxAttribute2.symbols b/tests/baselines/reference/contextuallyTypedJsxAttribute2.symbols index f8fb7991cb23b..0d9415509ce8e 100644 --- a/tests/baselines/reference/contextuallyTypedJsxAttribute2.symbols +++ b/tests/baselines/reference/contextuallyTypedJsxAttribute2.symbols @@ -16,7 +16,7 @@ function UnwrappedLink( >ElementType : Symbol(ElementType, Decl(contextuallyTypedJsxAttribute2.tsx, 3, 31)) >ElementType : Symbol(ElementType, Decl(contextuallyTypedJsxAttribute2.tsx, 3, 31)) - props: Omit, "as"> & { + props: Omit, "as">, >props : Symbol(props, Decl(contextuallyTypedJsxAttribute2.tsx, 5, 60)) >Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --)) >ComponentPropsWithRef : Symbol(ComponentPropsWithRef, Decl(contextuallyTypedJsxAttribute2.tsx, 3, 8)) @@ -24,9 +24,34 @@ function UnwrappedLink( >T : Symbol(T, Decl(contextuallyTypedJsxAttribute2.tsx, 5, 23)) >T : Symbol(T, Decl(contextuallyTypedJsxAttribute2.tsx, 5, 23)) +) { + return ; +>a : Symbol(JSX.IntrinsicElements.a, Decl(react16.d.ts, 2516, 41)) +>a : Symbol(JSX.IntrinsicElements.a, Decl(react16.d.ts, 2516, 41)) +} + + {}} />; +>UnwrappedLink : Symbol(UnwrappedLink, Decl(contextuallyTypedJsxAttribute2.tsx, 3, 59)) +>onClick : Symbol(onClick, Decl(contextuallyTypedJsxAttribute2.tsx, 11, 14)) +>e : Symbol(e, Decl(contextuallyTypedJsxAttribute2.tsx, 11, 25)) + +function UnwrappedLink2( +>UnwrappedLink2 : Symbol(UnwrappedLink2, Decl(contextuallyTypedJsxAttribute2.tsx, 11, 38)) +>T : Symbol(T, Decl(contextuallyTypedJsxAttribute2.tsx, 13, 24)) +>ElementType : Symbol(ElementType, Decl(contextuallyTypedJsxAttribute2.tsx, 3, 31)) +>ElementType : Symbol(ElementType, Decl(contextuallyTypedJsxAttribute2.tsx, 3, 31)) + + props: Omit, "as"> & { +>props : Symbol(props, Decl(contextuallyTypedJsxAttribute2.tsx, 13, 61)) +>Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --)) +>ComponentPropsWithRef : Symbol(ComponentPropsWithRef, Decl(contextuallyTypedJsxAttribute2.tsx, 3, 8)) +>ElementType : Symbol(ElementType, Decl(contextuallyTypedJsxAttribute2.tsx, 3, 31)) +>T : Symbol(T, Decl(contextuallyTypedJsxAttribute2.tsx, 13, 24)) +>T : Symbol(T, Decl(contextuallyTypedJsxAttribute2.tsx, 13, 24)) + as?: T; ->as : Symbol(as, Decl(contextuallyTypedJsxAttribute2.tsx, 6, 79)) ->T : Symbol(T, Decl(contextuallyTypedJsxAttribute2.tsx, 5, 23)) +>as : Symbol(as, Decl(contextuallyTypedJsxAttribute2.tsx, 14, 79)) +>T : Symbol(T, Decl(contextuallyTypedJsxAttribute2.tsx, 13, 24)) }, ) { @@ -35,14 +60,14 @@ function UnwrappedLink( >a : Symbol(JSX.IntrinsicElements.a, Decl(react16.d.ts, 2516, 41)) } - {}} />; ->UnwrappedLink : Symbol(UnwrappedLink, Decl(contextuallyTypedJsxAttribute2.tsx, 3, 59)) ->onClick : Symbol(onClick, Decl(contextuallyTypedJsxAttribute2.tsx, 13, 14)) ->e : Symbol(e, Decl(contextuallyTypedJsxAttribute2.tsx, 13, 25)) + {}} />; +>UnwrappedLink2 : Symbol(UnwrappedLink2, Decl(contextuallyTypedJsxAttribute2.tsx, 11, 38)) +>onClick : Symbol(onClick, Decl(contextuallyTypedJsxAttribute2.tsx, 21, 15)) +>e : Symbol(e, Decl(contextuallyTypedJsxAttribute2.tsx, 21, 26)) - {}} />; ->UnwrappedLink : Symbol(UnwrappedLink, Decl(contextuallyTypedJsxAttribute2.tsx, 3, 59)) ->as : Symbol(as, Decl(contextuallyTypedJsxAttribute2.tsx, 14, 14)) ->onClick : Symbol(onClick, Decl(contextuallyTypedJsxAttribute2.tsx, 14, 26)) ->e : Symbol(e, Decl(contextuallyTypedJsxAttribute2.tsx, 14, 37)) + {}} />; +>UnwrappedLink2 : Symbol(UnwrappedLink2, Decl(contextuallyTypedJsxAttribute2.tsx, 11, 38)) +>as : Symbol(as, Decl(contextuallyTypedJsxAttribute2.tsx, 22, 15)) +>onClick : Symbol(onClick, Decl(contextuallyTypedJsxAttribute2.tsx, 22, 27)) +>e : Symbol(e, Decl(contextuallyTypedJsxAttribute2.tsx, 22, 38)) diff --git a/tests/baselines/reference/contextuallyTypedJsxAttribute2.types b/tests/baselines/reference/contextuallyTypedJsxAttribute2.types index 05a6356dd284f..5fb6754f96150 100644 --- a/tests/baselines/reference/contextuallyTypedJsxAttribute2.types +++ b/tests/baselines/reference/contextuallyTypedJsxAttribute2.types @@ -11,7 +11,27 @@ import { ComponentPropsWithRef, ElementType } from "react"; >ElementType : any function UnwrappedLink( ->UnwrappedLink : (props: Omit, "as"> & { as?: T;}) => JSX.Element +>UnwrappedLink : (props: Omit, "as">) => JSX.Element + + props: Omit, "as">, +>props : Omit, "as"> + +) { + return ; +> : JSX.Element +>a : any +>a : any +} + + {}} />; +> {}} /> : JSX.Element +>UnwrappedLink : (props: Omit, "as">) => JSX.Element +>onClick : (e: React.MouseEvent) => void +>(e) => {} : (e: React.MouseEvent) => void +>e : React.MouseEvent + +function UnwrappedLink2( +>UnwrappedLink2 : (props: Omit, "as"> & { as?: T;}) => JSX.Element props: Omit, "as"> & { >props : Omit, "as"> & { as?: T | undefined; } @@ -27,16 +47,16 @@ function UnwrappedLink( >a : any } - {}} />; -> {}} /> : JSX.Element ->UnwrappedLink : (props: Omit, "as"> & { as?: T | undefined; }) => JSX.Element + {}} />; +> {}} /> : JSX.Element +>UnwrappedLink2 : (props: Omit, "as"> & { as?: T | undefined; }) => JSX.Element >onClick : (e: React.MouseEvent) => void >(e) => {} : (e: React.MouseEvent) => void >e : React.MouseEvent - {}} />; -> {}} /> : JSX.Element ->UnwrappedLink : (props: Omit, "as"> & { as?: T | undefined; }) => JSX.Element + {}} />; +> {}} /> : JSX.Element +>UnwrappedLink2 : (props: Omit, "as"> & { as?: T | undefined; }) => JSX.Element >as : "button" >onClick : (e: React.MouseEvent) => void >(e) => {} : (e: React.MouseEvent) => void diff --git a/tests/cases/compiler/contextuallyTypedJsxAttribute2.tsx b/tests/cases/compiler/contextuallyTypedJsxAttribute2.tsx index d94409f720ce0..003a44b6d8287 100644 --- a/tests/cases/compiler/contextuallyTypedJsxAttribute2.tsx +++ b/tests/cases/compiler/contextuallyTypedJsxAttribute2.tsx @@ -9,6 +9,14 @@ import React from "react"; import { ComponentPropsWithRef, ElementType } from "react"; function UnwrappedLink( + props: Omit, "as">, +) { + return ; +} + + {}} />; + +function UnwrappedLink2( props: Omit, "as"> & { as?: T; }, @@ -16,5 +24,5 @@ function UnwrappedLink( return ; } - {}} />; - {}} />; + {}} />; + {}} />;