Cherry-pick PR #38653 into release-3.9 (#38687)

Component commits:
97cb8188f0 No contextual types from circular mapped type properties

1dcf4ab32f Add regression test

Co-authored-by: Anders Hejlsberg <andersh@microsoft.com>
Co-authored-by: Wesley Wigham <wwigham@gmail.com>
This commit is contained in:
TypeScript Bot
2020-06-15 12:40:55 -07:00
committed by GitHub
parent 2fff325619
commit 9ec5fc5f35
5 changed files with 158 additions and 1 deletions

View File

@@ -22384,6 +22384,10 @@ namespace ts {
}
}
function isCircularMappedProperty(symbol: Symbol) {
return !!(getCheckFlags(symbol) & CheckFlags.Mapped && !(<MappedSymbol>symbol).type && findResolutionCycleStartIndex(symbol, TypeSystemPropertyName.Type) >= 0);
}
function getTypeOfPropertyOfContextualType(type: Type, name: __String) {
return mapType(type, t => {
if (isGenericMappedType(t)) {
@@ -22397,7 +22401,7 @@ namespace ts {
else if (t.flags & TypeFlags.StructuredType) {
const prop = getPropertyOfType(t, name);
if (prop) {
return getTypeOfSymbol(prop);
return isCircularMappedProperty(prop) ? undefined : getTypeOfSymbol(prop);
}
if (isTupleType(t)) {
const restType = getRestTypeOfTupleType(t);

View File

@@ -0,0 +1,32 @@
//// [circularContextualMappedType.ts]
type Func<T> = () => T;
type Mapped<T> = { [K in keyof T]: Func<T[K]> };
declare function reproduce(options: number): void;
declare function reproduce<T>(options: Mapped<T>): T
reproduce({
name: () => { return 123 }
});
reproduce({
name() { return 123 }
});
reproduce({
name: function () { return 123 }
});
//// [circularContextualMappedType.js]
"use strict";
reproduce({
name: function () { return 123; }
});
reproduce({
name: function () { return 123; }
});
reproduce({
name: function () { return 123; }
});

View File

@@ -0,0 +1,51 @@
=== tests/cases/compiler/circularContextualMappedType.ts ===
type Func<T> = () => T;
>Func : Symbol(Func, Decl(circularContextualMappedType.ts, 0, 0))
>T : Symbol(T, Decl(circularContextualMappedType.ts, 0, 10))
>T : Symbol(T, Decl(circularContextualMappedType.ts, 0, 10))
type Mapped<T> = { [K in keyof T]: Func<T[K]> };
>Mapped : Symbol(Mapped, Decl(circularContextualMappedType.ts, 0, 23))
>T : Symbol(T, Decl(circularContextualMappedType.ts, 2, 12))
>K : Symbol(K, Decl(circularContextualMappedType.ts, 2, 20))
>T : Symbol(T, Decl(circularContextualMappedType.ts, 2, 12))
>Func : Symbol(Func, Decl(circularContextualMappedType.ts, 0, 0))
>T : Symbol(T, Decl(circularContextualMappedType.ts, 2, 12))
>K : Symbol(K, Decl(circularContextualMappedType.ts, 2, 20))
declare function reproduce(options: number): void;
>reproduce : Symbol(reproduce, Decl(circularContextualMappedType.ts, 2, 48), Decl(circularContextualMappedType.ts, 4, 50))
>options : Symbol(options, Decl(circularContextualMappedType.ts, 4, 27))
declare function reproduce<T>(options: Mapped<T>): T
>reproduce : Symbol(reproduce, Decl(circularContextualMappedType.ts, 2, 48), Decl(circularContextualMappedType.ts, 4, 50))
>T : Symbol(T, Decl(circularContextualMappedType.ts, 5, 27))
>options : Symbol(options, Decl(circularContextualMappedType.ts, 5, 30))
>Mapped : Symbol(Mapped, Decl(circularContextualMappedType.ts, 0, 23))
>T : Symbol(T, Decl(circularContextualMappedType.ts, 5, 27))
>T : Symbol(T, Decl(circularContextualMappedType.ts, 5, 27))
reproduce({
>reproduce : Symbol(reproduce, Decl(circularContextualMappedType.ts, 2, 48), Decl(circularContextualMappedType.ts, 4, 50))
name: () => { return 123 }
>name : Symbol(name, Decl(circularContextualMappedType.ts, 7, 11))
});
reproduce({
>reproduce : Symbol(reproduce, Decl(circularContextualMappedType.ts, 2, 48), Decl(circularContextualMappedType.ts, 4, 50))
name() { return 123 }
>name : Symbol(name, Decl(circularContextualMappedType.ts, 11, 11))
});
reproduce({
>reproduce : Symbol(reproduce, Decl(circularContextualMappedType.ts, 2, 48), Decl(circularContextualMappedType.ts, 4, 50))
name: function () { return 123 }
>name : Symbol(name, Decl(circularContextualMappedType.ts, 15, 11))
});

View File

@@ -0,0 +1,50 @@
=== tests/cases/compiler/circularContextualMappedType.ts ===
type Func<T> = () => T;
>Func : Func<T>
type Mapped<T> = { [K in keyof T]: Func<T[K]> };
>Mapped : Mapped<T>
declare function reproduce(options: number): void;
>reproduce : { (options: number): void; <T>(options: Mapped<T>): T; }
>options : number
declare function reproduce<T>(options: Mapped<T>): T
>reproduce : { (options: number): void; <T>(options: Mapped<T>): T; }
>options : Mapped<T>
reproduce({
>reproduce({ name: () => { return 123 }}) : { name: number; }
>reproduce : { (options: number): void; <T>(options: Mapped<T>): T; }
>{ name: () => { return 123 }} : { name: () => number; }
name: () => { return 123 }
>name : () => number
>() => { return 123 } : () => number
>123 : 123
});
reproduce({
>reproduce({ name() { return 123 }}) : { name: number; }
>reproduce : { (options: number): void; <T>(options: Mapped<T>): T; }
>{ name() { return 123 }} : { name(): number; }
name() { return 123 }
>name : () => number
>123 : 123
});
reproduce({
>reproduce({ name: function () { return 123 }}) : { name: number; }
>reproduce : { (options: number): void; <T>(options: Mapped<T>): T; }
>{ name: function () { return 123 }} : { name: () => number; }
name: function () { return 123 }
>name : () => number
>function () { return 123 } : () => number
>123 : 123
});

View File

@@ -0,0 +1,20 @@
// @strict: true
type Func<T> = () => T;
type Mapped<T> = { [K in keyof T]: Func<T[K]> };
declare function reproduce(options: number): void;
declare function reproduce<T>(options: Mapped<T>): T
reproduce({
name: () => { return 123 }
});
reproduce({
name() { return 123 }
});
reproduce({
name: function () { return 123 }
});