diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 24d69b97611..b8d78b6efca 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10017,13 +10017,17 @@ namespace ts { // that substitutes the index type for P. For example, for an index access { [P in K]: Box }[X], we // construct the type Box. if (isGenericMappedType(objectType)) { - const mapper = createTypeMapper([getTypeParameterFromMappedType(objectType)], [type.indexType]); - const templateMapper = combineTypeMappers(objectType.mapper, mapper); - return type.simplified = mapType(instantiateType(getTemplateTypeFromMappedType(objectType), templateMapper), getSimplifiedType); + return type.simplified = mapType(substituteIndexedMappedType(objectType, type.indexType), getSimplifiedType); } return type.simplified = type; } + function substituteIndexedMappedType(objectType: MappedType, index: Type) { + const mapper = createTypeMapper([getTypeParameterFromMappedType(objectType)], [index]); + const templateMapper = combineTypeMappers(objectType.mapper, mapper); + return instantiateType(getTemplateTypeFromMappedType(objectType), templateMapper); + } + function getIndexedAccessType(objectType: Type, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression, missingType = accessNode ? errorType : unknownType): Type { if (objectType === wildcardType || indexType === wildcardType) { return wildcardType; @@ -17831,7 +17835,15 @@ namespace ts { function getTypeOfPropertyOfContextualType(type: Type, name: __String) { return mapType(type, t => { - if (t.flags & TypeFlags.StructuredType) { + if (isGenericMappedType(t)) { + const constraint = getConstraintTypeFromMappedType(t); + const constraintOfConstraint = getBaseConstraintOfType(constraint) || constraint; + const propertyNameType = getLiteralType(unescapeLeadingUnderscores(name)); + if (isTypeAssignableTo(propertyNameType, constraintOfConstraint)) { + return substituteIndexedMappedType(t, propertyNameType); + } + } + else if (t.flags & TypeFlags.StructuredType) { const prop = getPropertyOfType(t, name); if (prop) { return getTypeOfSymbol(prop); diff --git a/tests/baselines/reference/contextualPropertyOfGenericMappedType.js b/tests/baselines/reference/contextualPropertyOfGenericMappedType.js new file mode 100644 index 00000000000..f84fa97c463 --- /dev/null +++ b/tests/baselines/reference/contextualPropertyOfGenericMappedType.js @@ -0,0 +1,10 @@ +//// [contextualPropertyOfGenericMappedType.ts] +// Repro for #24694 + +declare function f(data: T, handlers: { [P in keyof T]: (value: T[P], prop: P) => void; }): void; +f({ data: 0 }, { data(value, key) {} }); + + +//// [contextualPropertyOfGenericMappedType.js] +// Repro for #24694 +f({ data: 0 }, { data: function (value, key) { } }); diff --git a/tests/baselines/reference/contextualPropertyOfGenericMappedType.symbols b/tests/baselines/reference/contextualPropertyOfGenericMappedType.symbols new file mode 100644 index 00000000000..beadc80bef6 --- /dev/null +++ b/tests/baselines/reference/contextualPropertyOfGenericMappedType.symbols @@ -0,0 +1,24 @@ +=== tests/cases/compiler/contextualPropertyOfGenericMappedType.ts === +// Repro for #24694 + +declare function f(data: T, handlers: { [P in keyof T]: (value: T[P], prop: P) => void; }): void; +>f : Symbol(f, Decl(contextualPropertyOfGenericMappedType.ts, 0, 0)) +>T : Symbol(T, Decl(contextualPropertyOfGenericMappedType.ts, 2, 19)) +>data : Symbol(data, Decl(contextualPropertyOfGenericMappedType.ts, 2, 37)) +>T : Symbol(T, Decl(contextualPropertyOfGenericMappedType.ts, 2, 19)) +>handlers : Symbol(handlers, Decl(contextualPropertyOfGenericMappedType.ts, 2, 45)) +>P : Symbol(P, Decl(contextualPropertyOfGenericMappedType.ts, 2, 59)) +>T : Symbol(T, Decl(contextualPropertyOfGenericMappedType.ts, 2, 19)) +>value : Symbol(value, Decl(contextualPropertyOfGenericMappedType.ts, 2, 75)) +>T : Symbol(T, Decl(contextualPropertyOfGenericMappedType.ts, 2, 19)) +>P : Symbol(P, Decl(contextualPropertyOfGenericMappedType.ts, 2, 59)) +>prop : Symbol(prop, Decl(contextualPropertyOfGenericMappedType.ts, 2, 87)) +>P : Symbol(P, Decl(contextualPropertyOfGenericMappedType.ts, 2, 59)) + +f({ data: 0 }, { data(value, key) {} }); +>f : Symbol(f, Decl(contextualPropertyOfGenericMappedType.ts, 0, 0)) +>data : Symbol(data, Decl(contextualPropertyOfGenericMappedType.ts, 3, 3)) +>data : Symbol(data, Decl(contextualPropertyOfGenericMappedType.ts, 3, 16)) +>value : Symbol(value, Decl(contextualPropertyOfGenericMappedType.ts, 3, 22)) +>key : Symbol(key, Decl(contextualPropertyOfGenericMappedType.ts, 3, 28)) + diff --git a/tests/baselines/reference/contextualPropertyOfGenericMappedType.types b/tests/baselines/reference/contextualPropertyOfGenericMappedType.types new file mode 100644 index 00000000000..c402f9e1fe6 --- /dev/null +++ b/tests/baselines/reference/contextualPropertyOfGenericMappedType.types @@ -0,0 +1,21 @@ +=== tests/cases/compiler/contextualPropertyOfGenericMappedType.ts === +// Repro for #24694 + +declare function f(data: T, handlers: { [P in keyof T]: (value: T[P], prop: P) => void; }): void; +>f : (data: T, handlers: { [P in keyof T]: (value: T[P], prop: P) => void; }) => void +>data : T +>handlers : { [P in keyof T]: (value: T[P], prop: P) => void; } +>value : T[P] +>prop : P + +f({ data: 0 }, { data(value, key) {} }); +>f({ data: 0 }, { data(value, key) {} }) : void +>f : (data: T, handlers: { [P in keyof T]: (value: T[P], prop: P) => void; }) => void +>{ data: 0 } : { data: number; } +>data : number +>0 : 0 +>{ data(value, key) {} } : { data(value: number, key: "data"): void; } +>data : (value: number, key: "data") => void +>value : number +>key : "data" + diff --git a/tests/baselines/reference/mappedTypeContextualTypesApplied.js b/tests/baselines/reference/mappedTypeContextualTypesApplied.js new file mode 100644 index 00000000000..ee838bade09 --- /dev/null +++ b/tests/baselines/reference/mappedTypeContextualTypesApplied.js @@ -0,0 +1,36 @@ +//// [mappedTypeContextualTypesApplied.ts] +type TakeString = (s: string) => any; + +// Various functions accepting an object whose properties are TakeString functions. +// Note these all use mapped types. +declare function mapped1(obj: T): void; +declare function mapped2(obj: T): void; +declare function mapped3(obj: T): void; +declare function mapped4(obj: T & {[P in keyof T]: TakeString}): void; +declare function mapped5(obj: T & {[P in K]: TakeString}): void; +declare function mapped6(obj: {[P in K]: TakeString}): void; +declare function mapped7(obj: {[P in K]: TakeString}): void; +declare function mapped8(obj: {[P in K]: TakeString}): void; +declare function mapped9(obj: {[P in K]: TakeString}): void; + +mapped1({foo: s => 42}); +mapped2({foo: s => 42}); +mapped3({foo: s => 42}); +mapped4({foo: s => 42}); +mapped5({foo: s => 42}); +mapped6({foo: s => 42}); +mapped7({foo: s => 42}); +mapped8({foo: s => 42}); +mapped9({foo: s => 42}); + +//// [mappedTypeContextualTypesApplied.js] +"use strict"; +mapped1({ foo: function (s) { return 42; } }); +mapped2({ foo: function (s) { return 42; } }); +mapped3({ foo: function (s) { return 42; } }); +mapped4({ foo: function (s) { return 42; } }); +mapped5({ foo: function (s) { return 42; } }); +mapped6({ foo: function (s) { return 42; } }); +mapped7({ foo: function (s) { return 42; } }); +mapped8({ foo: function (s) { return 42; } }); +mapped9({ foo: function (s) { return 42; } }); diff --git a/tests/baselines/reference/mappedTypeContextualTypesApplied.symbols b/tests/baselines/reference/mappedTypeContextualTypesApplied.symbols new file mode 100644 index 00000000000..6be9e881db3 --- /dev/null +++ b/tests/baselines/reference/mappedTypeContextualTypesApplied.symbols @@ -0,0 +1,129 @@ +=== tests/cases/compiler/mappedTypeContextualTypesApplied.ts === +type TakeString = (s: string) => any; +>TakeString : Symbol(TakeString, Decl(mappedTypeContextualTypesApplied.ts, 0, 0)) +>s : Symbol(s, Decl(mappedTypeContextualTypesApplied.ts, 0, 19)) + +// Various functions accepting an object whose properties are TakeString functions. +// Note these all use mapped types. +declare function mapped1(obj: T): void; +>mapped1 : Symbol(mapped1, Decl(mappedTypeContextualTypesApplied.ts, 0, 37)) +>T : Symbol(T, Decl(mappedTypeContextualTypesApplied.ts, 4, 25)) +>P : Symbol(P, Decl(mappedTypeContextualTypesApplied.ts, 4, 37)) +>TakeString : Symbol(TakeString, Decl(mappedTypeContextualTypesApplied.ts, 0, 0)) +>obj : Symbol(obj, Decl(mappedTypeContextualTypesApplied.ts, 4, 64)) +>T : Symbol(T, Decl(mappedTypeContextualTypesApplied.ts, 4, 25)) + +declare function mapped2(obj: T): void; +>mapped2 : Symbol(mapped2, Decl(mappedTypeContextualTypesApplied.ts, 4, 78)) +>T : Symbol(T, Decl(mappedTypeContextualTypesApplied.ts, 5, 25)) +>P : Symbol(P, Decl(mappedTypeContextualTypesApplied.ts, 5, 37)) +>T : Symbol(T, Decl(mappedTypeContextualTypesApplied.ts, 5, 25)) +>TakeString : Symbol(TakeString, Decl(mappedTypeContextualTypesApplied.ts, 0, 0)) +>obj : Symbol(obj, Decl(mappedTypeContextualTypesApplied.ts, 5, 65)) +>T : Symbol(T, Decl(mappedTypeContextualTypesApplied.ts, 5, 25)) + +declare function mapped3(obj: T): void; +>mapped3 : Symbol(mapped3, Decl(mappedTypeContextualTypesApplied.ts, 5, 79)) +>T : Symbol(T, Decl(mappedTypeContextualTypesApplied.ts, 6, 25)) +>P : Symbol(P, Decl(mappedTypeContextualTypesApplied.ts, 6, 37)) +>TakeString : Symbol(TakeString, Decl(mappedTypeContextualTypesApplied.ts, 0, 0)) +>obj : Symbol(obj, Decl(mappedTypeContextualTypesApplied.ts, 6, 67)) +>T : Symbol(T, Decl(mappedTypeContextualTypesApplied.ts, 6, 25)) + +declare function mapped4(obj: T & {[P in keyof T]: TakeString}): void; +>mapped4 : Symbol(mapped4, Decl(mappedTypeContextualTypesApplied.ts, 6, 81)) +>T : Symbol(T, Decl(mappedTypeContextualTypesApplied.ts, 7, 25)) +>obj : Symbol(obj, Decl(mappedTypeContextualTypesApplied.ts, 7, 28)) +>T : Symbol(T, Decl(mappedTypeContextualTypesApplied.ts, 7, 25)) +>P : Symbol(P, Decl(mappedTypeContextualTypesApplied.ts, 7, 39)) +>T : Symbol(T, Decl(mappedTypeContextualTypesApplied.ts, 7, 25)) +>TakeString : Symbol(TakeString, Decl(mappedTypeContextualTypesApplied.ts, 0, 0)) + +declare function mapped5(obj: T & {[P in K]: TakeString}): void; +>mapped5 : Symbol(mapped5, Decl(mappedTypeContextualTypesApplied.ts, 7, 73)) +>T : Symbol(T, Decl(mappedTypeContextualTypesApplied.ts, 8, 25)) +>K : Symbol(K, Decl(mappedTypeContextualTypesApplied.ts, 8, 27)) +>T : Symbol(T, Decl(mappedTypeContextualTypesApplied.ts, 8, 25)) +>obj : Symbol(obj, Decl(mappedTypeContextualTypesApplied.ts, 8, 47)) +>T : Symbol(T, Decl(mappedTypeContextualTypesApplied.ts, 8, 25)) +>P : Symbol(P, Decl(mappedTypeContextualTypesApplied.ts, 8, 58)) +>K : Symbol(K, Decl(mappedTypeContextualTypesApplied.ts, 8, 27)) +>TakeString : Symbol(TakeString, Decl(mappedTypeContextualTypesApplied.ts, 0, 0)) + +declare function mapped6(obj: {[P in K]: TakeString}): void; +>mapped6 : Symbol(mapped6, Decl(mappedTypeContextualTypesApplied.ts, 8, 86)) +>K : Symbol(K, Decl(mappedTypeContextualTypesApplied.ts, 9, 25)) +>obj : Symbol(obj, Decl(mappedTypeContextualTypesApplied.ts, 9, 43)) +>P : Symbol(P, Decl(mappedTypeContextualTypesApplied.ts, 9, 50)) +>K : Symbol(K, Decl(mappedTypeContextualTypesApplied.ts, 9, 25)) +>TakeString : Symbol(TakeString, Decl(mappedTypeContextualTypesApplied.ts, 0, 0)) + +declare function mapped7(obj: {[P in K]: TakeString}): void; +>mapped7 : Symbol(mapped7, Decl(mappedTypeContextualTypesApplied.ts, 9, 78)) +>K : Symbol(K, Decl(mappedTypeContextualTypesApplied.ts, 10, 25)) +>obj : Symbol(obj, Decl(mappedTypeContextualTypesApplied.ts, 10, 46)) +>P : Symbol(P, Decl(mappedTypeContextualTypesApplied.ts, 10, 53)) +>K : Symbol(K, Decl(mappedTypeContextualTypesApplied.ts, 10, 25)) +>TakeString : Symbol(TakeString, Decl(mappedTypeContextualTypesApplied.ts, 0, 0)) + +declare function mapped8(obj: {[P in K]: TakeString}): void; +>mapped8 : Symbol(mapped8, Decl(mappedTypeContextualTypesApplied.ts, 10, 81)) +>K : Symbol(K, Decl(mappedTypeContextualTypesApplied.ts, 11, 25)) +>obj : Symbol(obj, Decl(mappedTypeContextualTypesApplied.ts, 11, 42)) +>P : Symbol(P, Decl(mappedTypeContextualTypesApplied.ts, 11, 49)) +>K : Symbol(K, Decl(mappedTypeContextualTypesApplied.ts, 11, 25)) +>TakeString : Symbol(TakeString, Decl(mappedTypeContextualTypesApplied.ts, 0, 0)) + +declare function mapped9(obj: {[P in K]: TakeString}): void; +>mapped9 : Symbol(mapped9, Decl(mappedTypeContextualTypesApplied.ts, 11, 77)) +>K : Symbol(K, Decl(mappedTypeContextualTypesApplied.ts, 12, 25)) +>obj : Symbol(obj, Decl(mappedTypeContextualTypesApplied.ts, 12, 48)) +>P : Symbol(P, Decl(mappedTypeContextualTypesApplied.ts, 12, 55)) +>K : Symbol(K, Decl(mappedTypeContextualTypesApplied.ts, 12, 25)) +>TakeString : Symbol(TakeString, Decl(mappedTypeContextualTypesApplied.ts, 0, 0)) + +mapped1({foo: s => 42}); +>mapped1 : Symbol(mapped1, Decl(mappedTypeContextualTypesApplied.ts, 0, 37)) +>foo : Symbol(foo, Decl(mappedTypeContextualTypesApplied.ts, 14, 9)) +>s : Symbol(s, Decl(mappedTypeContextualTypesApplied.ts, 14, 13)) + +mapped2({foo: s => 42}); +>mapped2 : Symbol(mapped2, Decl(mappedTypeContextualTypesApplied.ts, 4, 78)) +>foo : Symbol(foo, Decl(mappedTypeContextualTypesApplied.ts, 15, 9)) +>s : Symbol(s, Decl(mappedTypeContextualTypesApplied.ts, 15, 13)) + +mapped3({foo: s => 42}); +>mapped3 : Symbol(mapped3, Decl(mappedTypeContextualTypesApplied.ts, 5, 79)) +>foo : Symbol(foo, Decl(mappedTypeContextualTypesApplied.ts, 16, 9)) +>s : Symbol(s, Decl(mappedTypeContextualTypesApplied.ts, 16, 13)) + +mapped4({foo: s => 42}); +>mapped4 : Symbol(mapped4, Decl(mappedTypeContextualTypesApplied.ts, 6, 81)) +>foo : Symbol(foo, Decl(mappedTypeContextualTypesApplied.ts, 17, 9)) +>s : Symbol(s, Decl(mappedTypeContextualTypesApplied.ts, 17, 13)) + +mapped5({foo: s => 42}); +>mapped5 : Symbol(mapped5, Decl(mappedTypeContextualTypesApplied.ts, 7, 73)) +>foo : Symbol(foo, Decl(mappedTypeContextualTypesApplied.ts, 18, 9)) +>s : Symbol(s, Decl(mappedTypeContextualTypesApplied.ts, 18, 13)) + +mapped6({foo: s => 42}); +>mapped6 : Symbol(mapped6, Decl(mappedTypeContextualTypesApplied.ts, 8, 86)) +>foo : Symbol(foo, Decl(mappedTypeContextualTypesApplied.ts, 19, 9)) +>s : Symbol(s, Decl(mappedTypeContextualTypesApplied.ts, 19, 13)) + +mapped7({foo: s => 42}); +>mapped7 : Symbol(mapped7, Decl(mappedTypeContextualTypesApplied.ts, 9, 78)) +>foo : Symbol(foo, Decl(mappedTypeContextualTypesApplied.ts, 20, 9)) +>s : Symbol(s, Decl(mappedTypeContextualTypesApplied.ts, 20, 13)) + +mapped8({foo: s => 42}); +>mapped8 : Symbol(mapped8, Decl(mappedTypeContextualTypesApplied.ts, 10, 81)) +>foo : Symbol(foo, Decl(mappedTypeContextualTypesApplied.ts, 21, 9)) +>s : Symbol(s, Decl(mappedTypeContextualTypesApplied.ts, 21, 13)) + +mapped9({foo: s => 42}); +>mapped9 : Symbol(mapped9, Decl(mappedTypeContextualTypesApplied.ts, 11, 77)) +>foo : Symbol(foo, Decl(mappedTypeContextualTypesApplied.ts, 22, 9)) +>s : Symbol(s, Decl(mappedTypeContextualTypesApplied.ts, 22, 13)) + diff --git a/tests/baselines/reference/mappedTypeContextualTypesApplied.types b/tests/baselines/reference/mappedTypeContextualTypesApplied.types new file mode 100644 index 00000000000..fc539785d1b --- /dev/null +++ b/tests/baselines/reference/mappedTypeContextualTypesApplied.types @@ -0,0 +1,124 @@ +=== tests/cases/compiler/mappedTypeContextualTypesApplied.ts === +type TakeString = (s: string) => any; +>TakeString : TakeString +>s : string + +// Various functions accepting an object whose properties are TakeString functions. +// Note these all use mapped types. +declare function mapped1(obj: T): void; +>mapped1 : (obj: T) => void +>obj : T + +declare function mapped2(obj: T): void; +>mapped2 : (obj: T) => void +>obj : T + +declare function mapped3(obj: T): void; +>mapped3 : (obj: T) => void +>obj : T + +declare function mapped4(obj: T & {[P in keyof T]: TakeString}): void; +>mapped4 : (obj: T & { [P in keyof T]: TakeString; }) => void +>obj : T & { [P in keyof T]: TakeString; } + +declare function mapped5(obj: T & {[P in K]: TakeString}): void; +>mapped5 : (obj: T & { [P in K]: TakeString; }) => void +>obj : T & { [P in K]: TakeString; } + +declare function mapped6(obj: {[P in K]: TakeString}): void; +>mapped6 : (obj: { [P in K]: TakeString; }) => void +>obj : { [P in K]: TakeString; } + +declare function mapped7(obj: {[P in K]: TakeString}): void; +>mapped7 : (obj: { [P in K]: TakeString; }) => void +>obj : { [P in K]: TakeString; } + +declare function mapped8(obj: {[P in K]: TakeString}): void; +>mapped8 : (obj: { [P in K]: TakeString; }) => void +>obj : { [P in K]: TakeString; } + +declare function mapped9(obj: {[P in K]: TakeString}): void; +>mapped9 : (obj: { [P in K]: TakeString; }) => void +>obj : { [P in K]: TakeString; } + +mapped1({foo: s => 42}); +>mapped1({foo: s => 42}) : void +>mapped1 : (obj: T) => void +>{foo: s => 42} : { foo: (s: string) => number; } +>foo : (s: string) => number +>s => 42 : (s: string) => number +>s : string +>42 : 42 + +mapped2({foo: s => 42}); +>mapped2({foo: s => 42}) : void +>mapped2 : (obj: T) => void +>{foo: s => 42} : { foo: (s: string) => number; } +>foo : (s: string) => number +>s => 42 : (s: string) => number +>s : string +>42 : 42 + +mapped3({foo: s => 42}); +>mapped3({foo: s => 42}) : void +>mapped3 : (obj: T) => void +>{foo: s => 42} : { foo: (s: string) => number; } +>foo : (s: string) => number +>s => 42 : (s: string) => number +>s : string +>42 : 42 + +mapped4({foo: s => 42}); +>mapped4({foo: s => 42}) : void +>mapped4 : (obj: T & { [P in keyof T]: TakeString; }) => void +>{foo: s => 42} : { foo: (s: string) => number; } +>foo : (s: string) => number +>s => 42 : (s: string) => number +>s : string +>42 : 42 + +mapped5({foo: s => 42}); +>mapped5({foo: s => 42}) : void +>mapped5 : (obj: T & { [P in K]: TakeString; }) => void +>{foo: s => 42} : { foo: (s: string) => number; } +>foo : (s: string) => number +>s => 42 : (s: string) => number +>s : string +>42 : 42 + +mapped6({foo: s => 42}); +>mapped6({foo: s => 42}) : void +>mapped6 : (obj: { [P in K]: TakeString; }) => void +>{foo: s => 42} : { foo: (s: string) => number; } +>foo : (s: string) => number +>s => 42 : (s: string) => number +>s : string +>42 : 42 + +mapped7({foo: s => 42}); +>mapped7({foo: s => 42}) : void +>mapped7 : (obj: { [P in K]: TakeString; }) => void +>{foo: s => 42} : { foo: (s: string) => number; } +>foo : (s: string) => number +>s => 42 : (s: string) => number +>s : string +>42 : 42 + +mapped8({foo: s => 42}); +>mapped8({foo: s => 42}) : void +>mapped8 : (obj: { [P in K]: TakeString; }) => void +>{foo: s => 42} : { foo: (s: string) => number; } +>foo : (s: string) => number +>s => 42 : (s: string) => number +>s : string +>42 : 42 + +mapped9({foo: s => 42}); +>mapped9({foo: s => 42}) : void +>mapped9 : (obj: { [P in K]: TakeString; }) => void +>{foo: s => 42} : { foo: (s: string) => number; } +>foo : (s: string) => number +>s => 42 : (s: string) => number +>s : string +>42 : 42 + diff --git a/tests/baselines/reference/reverseMappedContravariantInference.types b/tests/baselines/reference/reverseMappedContravariantInference.types index 1859ff6ea97..fa8a7dbdbf8 100644 --- a/tests/baselines/reference/reverseMappedContravariantInference.types +++ b/tests/baselines/reference/reverseMappedContravariantInference.types @@ -11,9 +11,9 @@ conforms({ foo: (v: string) => false })({ foo: "hello" }); >conforms({ foo: (v: string) => false })({ foo: "hello" }) : boolean >conforms({ foo: (v: string) => false }) : (value: { foo: string; }) => boolean >conforms : (source: { [K in keyof T]: (val: T[K]) => boolean; }) => (value: T) => boolean ->{ foo: (v: string) => false } : { foo: (v: string) => boolean; } ->foo : (v: string) => boolean ->(v: string) => false : (v: string) => boolean +>{ foo: (v: string) => false } : { foo: (v: string) => false; } +>foo : (v: string) => false +>(v: string) => false : (v: string) => false >v : string >false : false >{ foo: "hello" } : { foo: string; } diff --git a/tests/cases/compiler/contextualPropertyOfGenericMappedType.ts b/tests/cases/compiler/contextualPropertyOfGenericMappedType.ts new file mode 100644 index 00000000000..3e3e70fad3a --- /dev/null +++ b/tests/cases/compiler/contextualPropertyOfGenericMappedType.ts @@ -0,0 +1,5 @@ +// Repro for #24694 +// @noImplicitAny: true + +declare function f(data: T, handlers: { [P in keyof T]: (value: T[P], prop: P) => void; }): void; +f({ data: 0 }, { data(value, key) {} }); diff --git a/tests/cases/compiler/mappedTypeContextualTypesApplied.ts b/tests/cases/compiler/mappedTypeContextualTypesApplied.ts new file mode 100644 index 00000000000..5f11293b41e --- /dev/null +++ b/tests/cases/compiler/mappedTypeContextualTypesApplied.ts @@ -0,0 +1,24 @@ +// @strict: true +type TakeString = (s: string) => any; + +// Various functions accepting an object whose properties are TakeString functions. +// Note these all use mapped types. +declare function mapped1(obj: T): void; +declare function mapped2(obj: T): void; +declare function mapped3(obj: T): void; +declare function mapped4(obj: T & {[P in keyof T]: TakeString}): void; +declare function mapped5(obj: T & {[P in K]: TakeString}): void; +declare function mapped6(obj: {[P in K]: TakeString}): void; +declare function mapped7(obj: {[P in K]: TakeString}): void; +declare function mapped8(obj: {[P in K]: TakeString}): void; +declare function mapped9(obj: {[P in K]: TakeString}): void; + +mapped1({foo: s => 42}); +mapped2({foo: s => 42}); +mapped3({foo: s => 42}); +mapped4({foo: s => 42}); +mapped5({foo: s => 42}); +mapped6({foo: s => 42}); +mapped7({foo: s => 42}); +mapped8({foo: s => 42}); +mapped9({foo: s => 42}); \ No newline at end of file