From 5dfac15a94078245bab13dee007633fbef2eb6b0 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Thu, 15 Mar 2018 14:34:53 -0700 Subject: [PATCH 1/4] Improve type relation for recursive mapped types Recursive mapped types usually lead to the error "excess stack depth comparing types" because of a new type relation rule added in #19564 which says that "A source type T is related to a target type { [P in keyof T]: X } if T[P] is related to X". Unfortunately, with self-recursive mapped types like ```ts D = { [P in keyof T]: D } ``` we get infinite recursion when trying to assign a type parameter T to D, as T[P] is compared to D, T[P][P] is compared to D, and so on. We can avoid many of these infinite recursions by replacing occurrences of D in the template type with its type argument. This works because mapped types will completely cover the tree, so checking assignability of the top level implies that checking of lower level would succeed, even if there are infinitely many levels. For example: ```ts D = { [P in keyof T]: D | undefined } (t: T, dt: D) => { dt = t } ``` would previously check that `T[P]` is assignable to `D | undefined`. Now, after replacement, it checks that `T[P]` is assignable to `T[P] | undefined`. This implementation suffers from 3 limitations: 1. I use aliasSymbol to detect whether a type reference is a self-recursive one. This only works when the mapped type is at the top level of a type alias. 2. Not all instances of D are replaced with T, just those in intersections and unions. I think this covers almost all uses. 3. This doesn't fix #21048, which tries to assign an "off-by-one" partial-deep type to itself. Mostly fixes #21592. One repro there has a type alias to a union, and a mapped type is a member of the union. But this can be split into two aliases: ```ts type SafeAnyMap = { [K in keyof T]?: SafeAny = SafeAnyMap | boolean | string | symbol | number | null | undefined; ``` --- src/compiler/checker.ts | 37 +++++-- ...ecursiveMappedTypeAssignability.errors.txt | 43 ++++++++ .../recursiveMappedTypeAssignability.js | 55 ++++++++++ .../recursiveMappedTypeAssignability.symbols | 95 ++++++++++++++++ .../recursiveMappedTypeAssignability.types | 103 ++++++++++++++++++ .../recursiveMappedTypeAssignability.ts | 37 +++++++ 6 files changed, 358 insertions(+), 12 deletions(-) create mode 100644 tests/baselines/reference/recursiveMappedTypeAssignability.errors.txt create mode 100644 tests/baselines/reference/recursiveMappedTypeAssignability.js create mode 100644 tests/baselines/reference/recursiveMappedTypeAssignability.symbols create mode 100644 tests/baselines/reference/recursiveMappedTypeAssignability.types create mode 100644 tests/cases/compiler/recursiveMappedTypeAssignability.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4044e6ae1252f..3456e458a7b9c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10131,21 +10131,22 @@ namespace ts { const template = getTemplateTypeFromMappedType(target); const modifiers = getMappedTypeModifiers(target); if (!(modifiers & MappedTypeModifiers.ExcludeOptional)) { - if (template.flags & TypeFlags.IndexedAccess && (template).objectType === source && - (template).indexType === getTypeParameterFromMappedType(target)) { - return Ternary.True; - } - // A source type T is related to a target type { [P in keyof T]: X } if T[P] is related to X. - if (!isGenericMappedType(source) && getConstraintTypeFromMappedType(target) === getIndexType(source)) { - const indexedAccessType = getIndexedAccessType(source, getTypeParameterFromMappedType(target)); - const templateType = getTemplateTypeFromMappedType(target); - if (result = isRelatedTo(indexedAccessType, templateType, reportErrors)) { - errorInfo = saveErrorInfo; - return result; + if (template.flags & TypeFlags.IndexedAccess && (template).objectType === source && + (template).indexType === getTypeParameterFromMappedType(target)) { + return Ternary.True; + } + // A source type T is related to a target type { [P in keyof T]: X } if T[P] is related to X + // *after* occurrences of D in X are replaced with T[P]. + if (!isGenericMappedType(source) && getConstraintTypeFromMappedType(target) === getIndexType(source)) { + const indexedAccessType = getIndexedAccessType(source, getTypeParameterFromMappedType(target)); + const templateType = replaceRecursiveAliasReference(getTemplateTypeFromMappedType(target), target); + if (result = isRelatedTo(indexedAccessType, templateType, reportErrors)) { + errorInfo = saveErrorInfo; + return result; + } } } } - } if (source.flags & TypeFlags.TypeParameter) { let constraint = getConstraintForRelation(source); @@ -10292,6 +10293,18 @@ namespace ts { return Ternary.False; } + function replaceRecursiveAliasReference(template: Type, target: Type): Type { + return mapType(template, t => { + if (t.flags & TypeFlags.Intersection) { + return getIntersectionType((t as IntersectionType).types.map(u => replaceRecursiveAliasReference(u, target))) + } + const hasSharedAliasSymbol = t.aliasSymbol !== undefined && + t.aliasTypeArguments && t.aliasTypeArguments.length === 1 && + t.aliasSymbol === target.aliasSymbol; + return hasSharedAliasSymbol ? t.aliasTypeArguments[0] : t; + }); + } + // A type [P in S]: X is related to a type [Q in T]: Y if T is related to S and X' is // related to Y, where X' is an instantiation of X in which P is replaced with Q. Notice // that S and T are contra-variant whereas X and Y are co-variant. diff --git a/tests/baselines/reference/recursiveMappedTypeAssignability.errors.txt b/tests/baselines/reference/recursiveMappedTypeAssignability.errors.txt new file mode 100644 index 0000000000000..769b51c2f00ee --- /dev/null +++ b/tests/baselines/reference/recursiveMappedTypeAssignability.errors.txt @@ -0,0 +1,43 @@ +tests/cases/compiler/recursiveMappedTypeAssignability.ts(17,49): error TS2321: Excessive stack depth comparing types 'T[K]' and 'SafeAny'. + + +==== tests/cases/compiler/recursiveMappedTypeAssignability.ts (1 errors) ==== + // type D = { [P in keyof U]: D }; + // (t: T, dt: D) => { dt = t }; + // type DR = { readonly [P in keyof U]: DR }; + // (t: T, dt: DR) => { dt = t }; + // type DP = { [P in keyof U]?: DP }; + // (t: T, dt: DP) => { dt = t }; + // type DAP = { [P in keyof U]?: DAP & U[P] }; + // (t: T, dt: DAP) => { dt = t }; + + // #21592 + // doesn't work because aliasSymbol isn't set on the literal type + // since it's not top-level -- the union is. + type SafeAny = { + [K in keyof T]?: SafeAny + } | boolean | number | string | symbol | null | undefined + type DataValidator = { + [K in keyof T]?: (v: SafeAny) => v is T[K] + ~~~~ +!!! error TS2321: Excessive stack depth comparing types 'T[K]' and 'SafeAny'. + } + + // modified repro with top-level mapped type, which works + // because the literal type has aliasSymbol set + type SafeAny2 = { + [K in keyof T]?: SafeAny2 + } + (t: T, sat: SafeAny2) => { sat = t } + + + const fn = (arg: T) => { + ((arg2: RecursivePartial) => { + // ... + })(arg); + }; + + type RecursivePartial = { + [P in keyof T]?: RecursivePartial; + }; + \ No newline at end of file diff --git a/tests/baselines/reference/recursiveMappedTypeAssignability.js b/tests/baselines/reference/recursiveMappedTypeAssignability.js new file mode 100644 index 0000000000000..89e861763d432 --- /dev/null +++ b/tests/baselines/reference/recursiveMappedTypeAssignability.js @@ -0,0 +1,55 @@ +//// [recursiveMappedTypeAssignability.ts] +// type D = { [P in keyof U]: D }; +// (t: T, dt: D) => { dt = t }; +// type DR = { readonly [P in keyof U]: DR }; +// (t: T, dt: DR) => { dt = t }; +// type DP = { [P in keyof U]?: DP }; +// (t: T, dt: DP) => { dt = t }; +// type DAP = { [P in keyof U]?: DAP & U[P] }; +// (t: T, dt: DAP) => { dt = t }; + +// #21592 +// doesn't work because aliasSymbol isn't set on the literal type +// since it's not top-level -- the union is. +type SafeAny = { + [K in keyof T]?: SafeAny +} | boolean | number | string | symbol | null | undefined +type DataValidator = { + [K in keyof T]?: (v: SafeAny) => v is T[K] +} + +// modified repro with top-level mapped type, which works +// because the literal type has aliasSymbol set +type SafeAny2 = { + [K in keyof T]?: SafeAny2 +} +(t: T, sat: SafeAny2) => { sat = t } + + +const fn = (arg: T) => { + ((arg2: RecursivePartial) => { + // ... + })(arg); +}; + +type RecursivePartial = { + [P in keyof T]?: RecursivePartial; +}; + + +//// [recursiveMappedTypeAssignability.js] +"use strict"; +// type D = { [P in keyof U]: D }; +// (t: T, dt: D) => { dt = t }; +// type DR = { readonly [P in keyof U]: DR }; +// (t: T, dt: DR) => { dt = t }; +// type DP = { [P in keyof U]?: DP }; +// (t: T, dt: DP) => { dt = t }; +// type DAP = { [P in keyof U]?: DAP & U[P] }; +// (t: T, dt: DAP) => { dt = t }; +(function (t, sat) { sat = t; }); +var fn = function (arg) { + (function (arg2) { + // ... + })(arg); +}; diff --git a/tests/baselines/reference/recursiveMappedTypeAssignability.symbols b/tests/baselines/reference/recursiveMappedTypeAssignability.symbols new file mode 100644 index 0000000000000..7a5866febfaef --- /dev/null +++ b/tests/baselines/reference/recursiveMappedTypeAssignability.symbols @@ -0,0 +1,95 @@ +=== tests/cases/compiler/recursiveMappedTypeAssignability.ts === +// type D = { [P in keyof U]: D }; +// (t: T, dt: D) => { dt = t }; +// type DR = { readonly [P in keyof U]: DR }; +// (t: T, dt: DR) => { dt = t }; +// type DP = { [P in keyof U]?: DP }; +// (t: T, dt: DP) => { dt = t }; +// type DAP = { [P in keyof U]?: DAP & U[P] }; +// (t: T, dt: DAP) => { dt = t }; + +// #21592 +// doesn't work because aliasSymbol isn't set on the literal type +// since it's not top-level -- the union is. +type SafeAny = { +>SafeAny : Symbol(SafeAny, Decl(recursiveMappedTypeAssignability.ts, 0, 0)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 12, 13)) + + [K in keyof T]?: SafeAny +>K : Symbol(K, Decl(recursiveMappedTypeAssignability.ts, 13, 5)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 12, 13)) +>SafeAny : Symbol(SafeAny, Decl(recursiveMappedTypeAssignability.ts, 0, 0)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 12, 13)) +>K : Symbol(K, Decl(recursiveMappedTypeAssignability.ts, 13, 5)) + +} | boolean | number | string | symbol | null | undefined +type DataValidator = { +>DataValidator : Symbol(DataValidator, Decl(recursiveMappedTypeAssignability.ts, 14, 57)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 15, 19)) + + [K in keyof T]?: (v: SafeAny) => v is T[K] +>K : Symbol(K, Decl(recursiveMappedTypeAssignability.ts, 16, 5)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 15, 19)) +>v : Symbol(v, Decl(recursiveMappedTypeAssignability.ts, 16, 22)) +>SafeAny : Symbol(SafeAny, Decl(recursiveMappedTypeAssignability.ts, 0, 0)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 15, 19)) +>K : Symbol(K, Decl(recursiveMappedTypeAssignability.ts, 16, 5)) +>v : Symbol(v, Decl(recursiveMappedTypeAssignability.ts, 16, 22)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 15, 19)) +>K : Symbol(K, Decl(recursiveMappedTypeAssignability.ts, 16, 5)) +} + +// modified repro with top-level mapped type, which works +// because the literal type has aliasSymbol set +type SafeAny2 = { +>SafeAny2 : Symbol(SafeAny2, Decl(recursiveMappedTypeAssignability.ts, 17, 1)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 21, 14)) + + [K in keyof T]?: SafeAny2 +>K : Symbol(K, Decl(recursiveMappedTypeAssignability.ts, 22, 5)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 21, 14)) +>SafeAny2 : Symbol(SafeAny2, Decl(recursiveMappedTypeAssignability.ts, 17, 1)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 21, 14)) +>K : Symbol(K, Decl(recursiveMappedTypeAssignability.ts, 22, 5)) +} +(t: T, sat: SafeAny2) => { sat = t } +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 24, 1)) +>t : Symbol(t, Decl(recursiveMappedTypeAssignability.ts, 24, 4)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 24, 1)) +>sat : Symbol(sat, Decl(recursiveMappedTypeAssignability.ts, 24, 9)) +>SafeAny2 : Symbol(SafeAny2, Decl(recursiveMappedTypeAssignability.ts, 17, 1)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 24, 1)) +>sat : Symbol(sat, Decl(recursiveMappedTypeAssignability.ts, 24, 9)) +>t : Symbol(t, Decl(recursiveMappedTypeAssignability.ts, 24, 4)) + + +const fn = (arg: T) => { +>fn : Symbol(fn, Decl(recursiveMappedTypeAssignability.ts, 27, 5)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 27, 12)) +>arg : Symbol(arg, Decl(recursiveMappedTypeAssignability.ts, 27, 15)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 27, 12)) + + ((arg2: RecursivePartial) => { +>arg2 : Symbol(arg2, Decl(recursiveMappedTypeAssignability.ts, 28, 6)) +>RecursivePartial : Symbol(RecursivePartial, Decl(recursiveMappedTypeAssignability.ts, 31, 2)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 27, 12)) + + // ... + })(arg); +>arg : Symbol(arg, Decl(recursiveMappedTypeAssignability.ts, 27, 15)) + +}; + +type RecursivePartial = { +>RecursivePartial : Symbol(RecursivePartial, Decl(recursiveMappedTypeAssignability.ts, 31, 2)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 33, 22)) + + [P in keyof T]?: RecursivePartial; +>P : Symbol(P, Decl(recursiveMappedTypeAssignability.ts, 34, 5)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 33, 22)) +>RecursivePartial : Symbol(RecursivePartial, Decl(recursiveMappedTypeAssignability.ts, 31, 2)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 33, 22)) +>P : Symbol(P, Decl(recursiveMappedTypeAssignability.ts, 34, 5)) + +}; + diff --git a/tests/baselines/reference/recursiveMappedTypeAssignability.types b/tests/baselines/reference/recursiveMappedTypeAssignability.types new file mode 100644 index 0000000000000..676db899cc36d --- /dev/null +++ b/tests/baselines/reference/recursiveMappedTypeAssignability.types @@ -0,0 +1,103 @@ +=== tests/cases/compiler/recursiveMappedTypeAssignability.ts === +// type D = { [P in keyof U]: D }; +// (t: T, dt: D) => { dt = t }; +// type DR = { readonly [P in keyof U]: DR }; +// (t: T, dt: DR) => { dt = t }; +// type DP = { [P in keyof U]?: DP }; +// (t: T, dt: DP) => { dt = t }; +// type DAP = { [P in keyof U]?: DAP & U[P] }; +// (t: T, dt: DAP) => { dt = t }; + +// #21592 +// doesn't work because aliasSymbol isn't set on the literal type +// since it's not top-level -- the union is. +type SafeAny = { +>SafeAny : SafeAny +>T : T + + [K in keyof T]?: SafeAny +>K : K +>T : T +>SafeAny : SafeAny +>T : T +>K : K + +} | boolean | number | string | symbol | null | undefined +>null : null + +type DataValidator = { +>DataValidator : DataValidator +>T : T + + [K in keyof T]?: (v: SafeAny) => v is T[K] +>K : K +>T : T +>v : SafeAny +>SafeAny : SafeAny +>T : T +>K : K +>v : any +>T : T +>K : K +} + +// modified repro with top-level mapped type, which works +// because the literal type has aliasSymbol set +type SafeAny2 = { +>SafeAny2 : SafeAny2 +>T : T + + [K in keyof T]?: SafeAny2 +>K : K +>T : T +>SafeAny2 : SafeAny2 +>T : T +>K : K +} +(t: T, sat: SafeAny2) => { sat = t } +>(t: T, sat: SafeAny2) => { sat = t } : (t: T, sat: SafeAny2) => void +>T : T +>t : T +>T : T +>sat : SafeAny2 +>SafeAny2 : SafeAny2 +>T : T +>sat = t : T +>sat : SafeAny2 +>t : T + + +const fn = (arg: T) => { +>fn : (arg: T) => void +>(arg: T) => { ((arg2: RecursivePartial) => { // ... })(arg);} : (arg: T) => void +>T : T +>arg : T +>T : T + + ((arg2: RecursivePartial) => { +>((arg2: RecursivePartial) => { // ... })(arg) : void +>((arg2: RecursivePartial) => { // ... }) : (arg2: RecursivePartial) => void +>(arg2: RecursivePartial) => { // ... } : (arg2: RecursivePartial) => void +>arg2 : RecursivePartial +>RecursivePartial : RecursivePartial +>T : T + + // ... + })(arg); +>arg : T + +}; + +type RecursivePartial = { +>RecursivePartial : RecursivePartial +>T : T + + [P in keyof T]?: RecursivePartial; +>P : P +>T : T +>RecursivePartial : RecursivePartial +>T : T +>P : P + +}; + diff --git a/tests/cases/compiler/recursiveMappedTypeAssignability.ts b/tests/cases/compiler/recursiveMappedTypeAssignability.ts new file mode 100644 index 0000000000000..121933b1734dd --- /dev/null +++ b/tests/cases/compiler/recursiveMappedTypeAssignability.ts @@ -0,0 +1,37 @@ +// @strict: true +// type D = { [P in keyof U]: D }; +// (t: T, dt: D) => { dt = t }; +// type DR = { readonly [P in keyof U]: DR }; +// (t: T, dt: DR) => { dt = t }; +// type DP = { [P in keyof U]?: DP }; +// (t: T, dt: DP) => { dt = t }; +// type DAP = { [P in keyof U]?: DAP & U[P] }; +// (t: T, dt: DAP) => { dt = t }; + +// #21592 +// doesn't work because aliasSymbol isn't set on the literal type +// since it's not top-level -- the union is. +type SafeAny = { + [K in keyof T]?: SafeAny +} | boolean | number | string | symbol | null | undefined +type DataValidator = { + [K in keyof T]?: (v: SafeAny) => v is T[K] +} + +// modified repro with top-level mapped type, which works +// because the literal type has aliasSymbol set +type SafeAny2 = { + [K in keyof T]?: SafeAny2 +} +(t: T, sat: SafeAny2) => { sat = t } + + +const fn = (arg: T) => { + ((arg2: RecursivePartial) => { + // ... + })(arg); +}; + +type RecursivePartial = { + [P in keyof T]?: RecursivePartial; +}; From d535008849f4cb1972edb6505ad9af25ccdbbf0a Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Thu, 15 Mar 2018 14:51:38 -0700 Subject: [PATCH 2/4] Slight fix to new test --- ...ecursiveMappedTypeAssignability.errors.txt | 3 +- .../recursiveMappedTypeAssignability.js | 3 +- .../recursiveMappedTypeAssignability.symbols | 64 ++++++++++--------- .../recursiveMappedTypeAssignability.types | 11 +++- .../recursiveMappedTypeAssignability.ts | 3 +- 5 files changed, 50 insertions(+), 34 deletions(-) diff --git a/tests/baselines/reference/recursiveMappedTypeAssignability.errors.txt b/tests/baselines/reference/recursiveMappedTypeAssignability.errors.txt index 769b51c2f00ee..1f8a3ee264914 100644 --- a/tests/baselines/reference/recursiveMappedTypeAssignability.errors.txt +++ b/tests/baselines/reference/recursiveMappedTypeAssignability.errors.txt @@ -25,9 +25,10 @@ tests/cases/compiler/recursiveMappedTypeAssignability.ts(17,49): error TS2321: E // modified repro with top-level mapped type, which works // because the literal type has aliasSymbol set - type SafeAny2 = { + type SafeAnyMap = { [K in keyof T]?: SafeAny2 } + type SafeAny2 = SafeAnyMap | boolean | number | string | symbol | null | undefined (t: T, sat: SafeAny2) => { sat = t } diff --git a/tests/baselines/reference/recursiveMappedTypeAssignability.js b/tests/baselines/reference/recursiveMappedTypeAssignability.js index 89e861763d432..3e5d999087eff 100644 --- a/tests/baselines/reference/recursiveMappedTypeAssignability.js +++ b/tests/baselines/reference/recursiveMappedTypeAssignability.js @@ -20,9 +20,10 @@ type DataValidator = { // modified repro with top-level mapped type, which works // because the literal type has aliasSymbol set -type SafeAny2 = { +type SafeAnyMap = { [K in keyof T]?: SafeAny2 } +type SafeAny2 = SafeAnyMap | boolean | number | string | symbol | null | undefined (t: T, sat: SafeAny2) => { sat = t } diff --git a/tests/baselines/reference/recursiveMappedTypeAssignability.symbols b/tests/baselines/reference/recursiveMappedTypeAssignability.symbols index 7a5866febfaef..1cd5809cde92b 100644 --- a/tests/baselines/reference/recursiveMappedTypeAssignability.symbols +++ b/tests/baselines/reference/recursiveMappedTypeAssignability.symbols @@ -41,55 +41,61 @@ type DataValidator = { // modified repro with top-level mapped type, which works // because the literal type has aliasSymbol set -type SafeAny2 = { ->SafeAny2 : Symbol(SafeAny2, Decl(recursiveMappedTypeAssignability.ts, 17, 1)) ->T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 21, 14)) +type SafeAnyMap = { +>SafeAnyMap : Symbol(SafeAnyMap, Decl(recursiveMappedTypeAssignability.ts, 17, 1)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 21, 16)) [K in keyof T]?: SafeAny2 >K : Symbol(K, Decl(recursiveMappedTypeAssignability.ts, 22, 5)) ->T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 21, 14)) ->SafeAny2 : Symbol(SafeAny2, Decl(recursiveMappedTypeAssignability.ts, 17, 1)) ->T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 21, 14)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 21, 16)) +>SafeAny2 : Symbol(SafeAny2, Decl(recursiveMappedTypeAssignability.ts, 23, 1)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 21, 16)) >K : Symbol(K, Decl(recursiveMappedTypeAssignability.ts, 22, 5)) } +type SafeAny2 = SafeAnyMap | boolean | number | string | symbol | null | undefined +>SafeAny2 : Symbol(SafeAny2, Decl(recursiveMappedTypeAssignability.ts, 23, 1)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 24, 14)) +>SafeAnyMap : Symbol(SafeAnyMap, Decl(recursiveMappedTypeAssignability.ts, 17, 1)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 24, 14)) + (t: T, sat: SafeAny2) => { sat = t } ->T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 24, 1)) ->t : Symbol(t, Decl(recursiveMappedTypeAssignability.ts, 24, 4)) ->T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 24, 1)) ->sat : Symbol(sat, Decl(recursiveMappedTypeAssignability.ts, 24, 9)) ->SafeAny2 : Symbol(SafeAny2, Decl(recursiveMappedTypeAssignability.ts, 17, 1)) ->T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 24, 1)) ->sat : Symbol(sat, Decl(recursiveMappedTypeAssignability.ts, 24, 9)) ->t : Symbol(t, Decl(recursiveMappedTypeAssignability.ts, 24, 4)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 25, 1)) +>t : Symbol(t, Decl(recursiveMappedTypeAssignability.ts, 25, 4)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 25, 1)) +>sat : Symbol(sat, Decl(recursiveMappedTypeAssignability.ts, 25, 9)) +>SafeAny2 : Symbol(SafeAny2, Decl(recursiveMappedTypeAssignability.ts, 23, 1)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 25, 1)) +>sat : Symbol(sat, Decl(recursiveMappedTypeAssignability.ts, 25, 9)) +>t : Symbol(t, Decl(recursiveMappedTypeAssignability.ts, 25, 4)) const fn = (arg: T) => { ->fn : Symbol(fn, Decl(recursiveMappedTypeAssignability.ts, 27, 5)) ->T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 27, 12)) ->arg : Symbol(arg, Decl(recursiveMappedTypeAssignability.ts, 27, 15)) ->T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 27, 12)) +>fn : Symbol(fn, Decl(recursiveMappedTypeAssignability.ts, 28, 5)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 28, 12)) +>arg : Symbol(arg, Decl(recursiveMappedTypeAssignability.ts, 28, 15)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 28, 12)) ((arg2: RecursivePartial) => { ->arg2 : Symbol(arg2, Decl(recursiveMappedTypeAssignability.ts, 28, 6)) ->RecursivePartial : Symbol(RecursivePartial, Decl(recursiveMappedTypeAssignability.ts, 31, 2)) ->T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 27, 12)) +>arg2 : Symbol(arg2, Decl(recursiveMappedTypeAssignability.ts, 29, 6)) +>RecursivePartial : Symbol(RecursivePartial, Decl(recursiveMappedTypeAssignability.ts, 32, 2)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 28, 12)) // ... })(arg); ->arg : Symbol(arg, Decl(recursiveMappedTypeAssignability.ts, 27, 15)) +>arg : Symbol(arg, Decl(recursiveMappedTypeAssignability.ts, 28, 15)) }; type RecursivePartial = { ->RecursivePartial : Symbol(RecursivePartial, Decl(recursiveMappedTypeAssignability.ts, 31, 2)) ->T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 33, 22)) +>RecursivePartial : Symbol(RecursivePartial, Decl(recursiveMappedTypeAssignability.ts, 32, 2)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 34, 22)) [P in keyof T]?: RecursivePartial; ->P : Symbol(P, Decl(recursiveMappedTypeAssignability.ts, 34, 5)) ->T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 33, 22)) ->RecursivePartial : Symbol(RecursivePartial, Decl(recursiveMappedTypeAssignability.ts, 31, 2)) ->T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 33, 22)) ->P : Symbol(P, Decl(recursiveMappedTypeAssignability.ts, 34, 5)) +>P : Symbol(P, Decl(recursiveMappedTypeAssignability.ts, 35, 5)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 34, 22)) +>RecursivePartial : Symbol(RecursivePartial, Decl(recursiveMappedTypeAssignability.ts, 32, 2)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 34, 22)) +>P : Symbol(P, Decl(recursiveMappedTypeAssignability.ts, 35, 5)) }; diff --git a/tests/baselines/reference/recursiveMappedTypeAssignability.types b/tests/baselines/reference/recursiveMappedTypeAssignability.types index 676db899cc36d..1c6d37034f59b 100644 --- a/tests/baselines/reference/recursiveMappedTypeAssignability.types +++ b/tests/baselines/reference/recursiveMappedTypeAssignability.types @@ -43,8 +43,8 @@ type DataValidator = { // modified repro with top-level mapped type, which works // because the literal type has aliasSymbol set -type SafeAny2 = { ->SafeAny2 : SafeAny2 +type SafeAnyMap = { +>SafeAnyMap : SafeAnyMap >T : T [K in keyof T]?: SafeAny2 @@ -54,6 +54,13 @@ type SafeAny2 = { >T : T >K : K } +type SafeAny2 = SafeAnyMap | boolean | number | string | symbol | null | undefined +>SafeAny2 : SafeAny2 +>T : T +>SafeAnyMap : SafeAnyMap +>T : T +>null : null + (t: T, sat: SafeAny2) => { sat = t } >(t: T, sat: SafeAny2) => { sat = t } : (t: T, sat: SafeAny2) => void >T : T diff --git a/tests/cases/compiler/recursiveMappedTypeAssignability.ts b/tests/cases/compiler/recursiveMappedTypeAssignability.ts index 121933b1734dd..d603f97040774 100644 --- a/tests/cases/compiler/recursiveMappedTypeAssignability.ts +++ b/tests/cases/compiler/recursiveMappedTypeAssignability.ts @@ -20,9 +20,10 @@ type DataValidator = { // modified repro with top-level mapped type, which works // because the literal type has aliasSymbol set -type SafeAny2 = { +type SafeAnyMap = { [K in keyof T]?: SafeAny2 } +type SafeAny2 = SafeAnyMap | boolean | number | string | symbol | null | undefined (t: T, sat: SafeAny2) => { sat = t } From ea3cbc23bb0b6062c86ba17b74cb931291b4b320 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Thu, 15 Mar 2018 14:54:16 -0700 Subject: [PATCH 3/4] Even more test updates --- ...ecursiveMappedTypeAssignability.errors.txt | 16 ++-- .../recursiveMappedTypeAssignability.js | 28 +++--- .../recursiveMappedTypeAssignability.symbols | 91 +++++++++++++++--- .../recursiveMappedTypeAssignability.types | 93 +++++++++++++++++-- .../recursiveMappedTypeAssignability.ts | 16 ++-- 5 files changed, 193 insertions(+), 51 deletions(-) diff --git a/tests/baselines/reference/recursiveMappedTypeAssignability.errors.txt b/tests/baselines/reference/recursiveMappedTypeAssignability.errors.txt index 1f8a3ee264914..b73b852a5d3c3 100644 --- a/tests/baselines/reference/recursiveMappedTypeAssignability.errors.txt +++ b/tests/baselines/reference/recursiveMappedTypeAssignability.errors.txt @@ -2,14 +2,14 @@ tests/cases/compiler/recursiveMappedTypeAssignability.ts(17,49): error TS2321: E ==== tests/cases/compiler/recursiveMappedTypeAssignability.ts (1 errors) ==== - // type D = { [P in keyof U]: D }; - // (t: T, dt: D) => { dt = t }; - // type DR = { readonly [P in keyof U]: DR }; - // (t: T, dt: DR) => { dt = t }; - // type DP = { [P in keyof U]?: DP }; - // (t: T, dt: DP) => { dt = t }; - // type DAP = { [P in keyof U]?: DAP & U[P] }; - // (t: T, dt: DAP) => { dt = t }; + type D = { [P in keyof U]: D }; + (t: T, dt: D) => { dt = t }; + type DR = { readonly [P in keyof U]: DR }; + (t: T, dt: DR) => { dt = t }; + type DP = { [P in keyof U]?: DP }; + (t: T, dt: DP) => { dt = t }; + type DAP = { [P in keyof U]?: DAP & U[P] }; + (t: T, dt: DAP) => { dt = t }; // #21592 // doesn't work because aliasSymbol isn't set on the literal type diff --git a/tests/baselines/reference/recursiveMappedTypeAssignability.js b/tests/baselines/reference/recursiveMappedTypeAssignability.js index 3e5d999087eff..ace260fa1baaf 100644 --- a/tests/baselines/reference/recursiveMappedTypeAssignability.js +++ b/tests/baselines/reference/recursiveMappedTypeAssignability.js @@ -1,12 +1,12 @@ //// [recursiveMappedTypeAssignability.ts] -// type D = { [P in keyof U]: D }; -// (t: T, dt: D) => { dt = t }; -// type DR = { readonly [P in keyof U]: DR }; -// (t: T, dt: DR) => { dt = t }; -// type DP = { [P in keyof U]?: DP }; -// (t: T, dt: DP) => { dt = t }; -// type DAP = { [P in keyof U]?: DAP & U[P] }; -// (t: T, dt: DAP) => { dt = t }; +type D = { [P in keyof U]: D }; +(t: T, dt: D) => { dt = t }; +type DR = { readonly [P in keyof U]: DR }; +(t: T, dt: DR) => { dt = t }; +type DP = { [P in keyof U]?: DP }; +(t: T, dt: DP) => { dt = t }; +type DAP = { [P in keyof U]?: DAP & U[P] }; +(t: T, dt: DAP) => { dt = t }; // #21592 // doesn't work because aliasSymbol isn't set on the literal type @@ -40,14 +40,10 @@ type RecursivePartial = { //// [recursiveMappedTypeAssignability.js] "use strict"; -// type D = { [P in keyof U]: D }; -// (t: T, dt: D) => { dt = t }; -// type DR = { readonly [P in keyof U]: DR }; -// (t: T, dt: DR) => { dt = t }; -// type DP = { [P in keyof U]?: DP }; -// (t: T, dt: DP) => { dt = t }; -// type DAP = { [P in keyof U]?: DAP & U[P] }; -// (t: T, dt: DAP) => { dt = t }; +(function (t, dt) { dt = t; }); +(function (t, dt) { dt = t; }); +(function (t, dt) { dt = t; }); +(function (t, dt) { dt = t; }); (function (t, sat) { sat = t; }); var fn = function (arg) { (function (arg2) { diff --git a/tests/baselines/reference/recursiveMappedTypeAssignability.symbols b/tests/baselines/reference/recursiveMappedTypeAssignability.symbols index 1cd5809cde92b..50539f3852f7f 100644 --- a/tests/baselines/reference/recursiveMappedTypeAssignability.symbols +++ b/tests/baselines/reference/recursiveMappedTypeAssignability.symbols @@ -1,24 +1,93 @@ === tests/cases/compiler/recursiveMappedTypeAssignability.ts === -// type D = { [P in keyof U]: D }; -// (t: T, dt: D) => { dt = t }; -// type DR = { readonly [P in keyof U]: DR }; -// (t: T, dt: DR) => { dt = t }; -// type DP = { [P in keyof U]?: DP }; -// (t: T, dt: DP) => { dt = t }; -// type DAP = { [P in keyof U]?: DAP & U[P] }; -// (t: T, dt: DAP) => { dt = t }; +type D = { [P in keyof U]: D }; +>D : Symbol(D, Decl(recursiveMappedTypeAssignability.ts, 0, 0)) +>U : Symbol(U, Decl(recursiveMappedTypeAssignability.ts, 0, 7)) +>P : Symbol(P, Decl(recursiveMappedTypeAssignability.ts, 0, 15)) +>U : Symbol(U, Decl(recursiveMappedTypeAssignability.ts, 0, 7)) +>D : Symbol(D, Decl(recursiveMappedTypeAssignability.ts, 0, 0)) +>U : Symbol(U, Decl(recursiveMappedTypeAssignability.ts, 0, 7)) +>P : Symbol(P, Decl(recursiveMappedTypeAssignability.ts, 0, 15)) + +(t: T, dt: D) => { dt = t }; +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 1, 1)) +>t : Symbol(t, Decl(recursiveMappedTypeAssignability.ts, 1, 4)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 1, 1)) +>dt : Symbol(dt, Decl(recursiveMappedTypeAssignability.ts, 1, 9)) +>D : Symbol(D, Decl(recursiveMappedTypeAssignability.ts, 0, 0)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 1, 1)) +>dt : Symbol(dt, Decl(recursiveMappedTypeAssignability.ts, 1, 9)) +>t : Symbol(t, Decl(recursiveMappedTypeAssignability.ts, 1, 4)) + +type DR = { readonly [P in keyof U]: DR }; +>DR : Symbol(DR, Decl(recursiveMappedTypeAssignability.ts, 1, 34)) +>U : Symbol(U, Decl(recursiveMappedTypeAssignability.ts, 2, 8)) +>P : Symbol(P, Decl(recursiveMappedTypeAssignability.ts, 2, 25)) +>U : Symbol(U, Decl(recursiveMappedTypeAssignability.ts, 2, 8)) +>DR : Symbol(DR, Decl(recursiveMappedTypeAssignability.ts, 1, 34)) +>U : Symbol(U, Decl(recursiveMappedTypeAssignability.ts, 2, 8)) +>P : Symbol(P, Decl(recursiveMappedTypeAssignability.ts, 2, 25)) + +(t: T, dt: DR) => { dt = t }; +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 3, 1)) +>t : Symbol(t, Decl(recursiveMappedTypeAssignability.ts, 3, 4)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 3, 1)) +>dt : Symbol(dt, Decl(recursiveMappedTypeAssignability.ts, 3, 9)) +>DR : Symbol(DR, Decl(recursiveMappedTypeAssignability.ts, 1, 34)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 3, 1)) +>dt : Symbol(dt, Decl(recursiveMappedTypeAssignability.ts, 3, 9)) +>t : Symbol(t, Decl(recursiveMappedTypeAssignability.ts, 3, 4)) + +type DP = { [P in keyof U]?: DP }; +>DP : Symbol(DP, Decl(recursiveMappedTypeAssignability.ts, 3, 35)) +>U : Symbol(U, Decl(recursiveMappedTypeAssignability.ts, 4, 8)) +>P : Symbol(P, Decl(recursiveMappedTypeAssignability.ts, 4, 16)) +>U : Symbol(U, Decl(recursiveMappedTypeAssignability.ts, 4, 8)) +>DP : Symbol(DP, Decl(recursiveMappedTypeAssignability.ts, 3, 35)) +>U : Symbol(U, Decl(recursiveMappedTypeAssignability.ts, 4, 8)) +>P : Symbol(P, Decl(recursiveMappedTypeAssignability.ts, 4, 16)) + +(t: T, dt: DP) => { dt = t }; +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 5, 1)) +>t : Symbol(t, Decl(recursiveMappedTypeAssignability.ts, 5, 4)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 5, 1)) +>dt : Symbol(dt, Decl(recursiveMappedTypeAssignability.ts, 5, 9)) +>DP : Symbol(DP, Decl(recursiveMappedTypeAssignability.ts, 3, 35)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 5, 1)) +>dt : Symbol(dt, Decl(recursiveMappedTypeAssignability.ts, 5, 9)) +>t : Symbol(t, Decl(recursiveMappedTypeAssignability.ts, 5, 4)) + +type DAP = { [P in keyof U]?: DAP & U[P] }; +>DAP : Symbol(DAP, Decl(recursiveMappedTypeAssignability.ts, 5, 35)) +>U : Symbol(U, Decl(recursiveMappedTypeAssignability.ts, 6, 9)) +>P : Symbol(P, Decl(recursiveMappedTypeAssignability.ts, 6, 17)) +>U : Symbol(U, Decl(recursiveMappedTypeAssignability.ts, 6, 9)) +>DAP : Symbol(DAP, Decl(recursiveMappedTypeAssignability.ts, 5, 35)) +>U : Symbol(U, Decl(recursiveMappedTypeAssignability.ts, 6, 9)) +>P : Symbol(P, Decl(recursiveMappedTypeAssignability.ts, 6, 17)) +>U : Symbol(U, Decl(recursiveMappedTypeAssignability.ts, 6, 9)) +>P : Symbol(P, Decl(recursiveMappedTypeAssignability.ts, 6, 17)) + +(t: T, dt: DAP) => { dt = t }; +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 7, 1)) +>t : Symbol(t, Decl(recursiveMappedTypeAssignability.ts, 7, 4)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 7, 1)) +>dt : Symbol(dt, Decl(recursiveMappedTypeAssignability.ts, 7, 9)) +>DAP : Symbol(DAP, Decl(recursiveMappedTypeAssignability.ts, 5, 35)) +>T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 7, 1)) +>dt : Symbol(dt, Decl(recursiveMappedTypeAssignability.ts, 7, 9)) +>t : Symbol(t, Decl(recursiveMappedTypeAssignability.ts, 7, 4)) // #21592 // doesn't work because aliasSymbol isn't set on the literal type // since it's not top-level -- the union is. type SafeAny = { ->SafeAny : Symbol(SafeAny, Decl(recursiveMappedTypeAssignability.ts, 0, 0)) +>SafeAny : Symbol(SafeAny, Decl(recursiveMappedTypeAssignability.ts, 7, 36)) >T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 12, 13)) [K in keyof T]?: SafeAny >K : Symbol(K, Decl(recursiveMappedTypeAssignability.ts, 13, 5)) >T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 12, 13)) ->SafeAny : Symbol(SafeAny, Decl(recursiveMappedTypeAssignability.ts, 0, 0)) +>SafeAny : Symbol(SafeAny, Decl(recursiveMappedTypeAssignability.ts, 7, 36)) >T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 12, 13)) >K : Symbol(K, Decl(recursiveMappedTypeAssignability.ts, 13, 5)) @@ -31,7 +100,7 @@ type DataValidator = { >K : Symbol(K, Decl(recursiveMappedTypeAssignability.ts, 16, 5)) >T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 15, 19)) >v : Symbol(v, Decl(recursiveMappedTypeAssignability.ts, 16, 22)) ->SafeAny : Symbol(SafeAny, Decl(recursiveMappedTypeAssignability.ts, 0, 0)) +>SafeAny : Symbol(SafeAny, Decl(recursiveMappedTypeAssignability.ts, 7, 36)) >T : Symbol(T, Decl(recursiveMappedTypeAssignability.ts, 15, 19)) >K : Symbol(K, Decl(recursiveMappedTypeAssignability.ts, 16, 5)) >v : Symbol(v, Decl(recursiveMappedTypeAssignability.ts, 16, 22)) diff --git a/tests/baselines/reference/recursiveMappedTypeAssignability.types b/tests/baselines/reference/recursiveMappedTypeAssignability.types index 1c6d37034f59b..87332752dce93 100644 --- a/tests/baselines/reference/recursiveMappedTypeAssignability.types +++ b/tests/baselines/reference/recursiveMappedTypeAssignability.types @@ -1,12 +1,89 @@ === tests/cases/compiler/recursiveMappedTypeAssignability.ts === -// type D = { [P in keyof U]: D }; -// (t: T, dt: D) => { dt = t }; -// type DR = { readonly [P in keyof U]: DR }; -// (t: T, dt: DR) => { dt = t }; -// type DP = { [P in keyof U]?: DP }; -// (t: T, dt: DP) => { dt = t }; -// type DAP = { [P in keyof U]?: DAP & U[P] }; -// (t: T, dt: DAP) => { dt = t }; +type D = { [P in keyof U]: D }; +>D : D +>U : U +>P : P +>U : U +>D : D +>U : U +>P : P + +(t: T, dt: D) => { dt = t }; +>(t: T, dt: D) => { dt = t } : (t: T, dt: D) => void +>T : T +>t : T +>T : T +>dt : D +>D : D +>T : T +>dt = t : T +>dt : D +>t : T + +type DR = { readonly [P in keyof U]: DR }; +>DR : DR +>U : U +>P : P +>U : U +>DR : DR +>U : U +>P : P + +(t: T, dt: DR) => { dt = t }; +>(t: T, dt: DR) => { dt = t } : (t: T, dt: DR) => void +>T : T +>t : T +>T : T +>dt : DR +>DR : DR +>T : T +>dt = t : T +>dt : DR +>t : T + +type DP = { [P in keyof U]?: DP }; +>DP : DP +>U : U +>P : P +>U : U +>DP : DP +>U : U +>P : P + +(t: T, dt: DP) => { dt = t }; +>(t: T, dt: DP) => { dt = t } : (t: T, dt: DP) => void +>T : T +>t : T +>T : T +>dt : DP +>DP : DP +>T : T +>dt = t : T +>dt : DP +>t : T + +type DAP = { [P in keyof U]?: DAP & U[P] }; +>DAP : DAP +>U : U +>P : P +>U : U +>DAP : DAP +>U : U +>P : P +>U : U +>P : P + +(t: T, dt: DAP) => { dt = t }; +>(t: T, dt: DAP) => { dt = t } : (t: T, dt: DAP) => void +>T : T +>t : T +>T : T +>dt : DAP +>DAP : DAP +>T : T +>dt = t : T +>dt : DAP +>t : T // #21592 // doesn't work because aliasSymbol isn't set on the literal type diff --git a/tests/cases/compiler/recursiveMappedTypeAssignability.ts b/tests/cases/compiler/recursiveMappedTypeAssignability.ts index d603f97040774..71fc89945bd0d 100644 --- a/tests/cases/compiler/recursiveMappedTypeAssignability.ts +++ b/tests/cases/compiler/recursiveMappedTypeAssignability.ts @@ -1,12 +1,12 @@ // @strict: true -// type D = { [P in keyof U]: D }; -// (t: T, dt: D) => { dt = t }; -// type DR = { readonly [P in keyof U]: DR }; -// (t: T, dt: DR) => { dt = t }; -// type DP = { [P in keyof U]?: DP }; -// (t: T, dt: DP) => { dt = t }; -// type DAP = { [P in keyof U]?: DAP & U[P] }; -// (t: T, dt: DAP) => { dt = t }; +type D = { [P in keyof U]: D }; +(t: T, dt: D) => { dt = t }; +type DR = { readonly [P in keyof U]: DR }; +(t: T, dt: DR) => { dt = t }; +type DP = { [P in keyof U]?: DP }; +(t: T, dt: DP) => { dt = t }; +type DAP = { [P in keyof U]?: DAP & U[P] }; +(t: T, dt: DAP) => { dt = t }; // #21592 // doesn't work because aliasSymbol isn't set on the literal type From 289c762e11d4330cfb3e5d3a65cda7062369a5a4 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Mon, 19 Mar 2018 16:16:16 -0700 Subject: [PATCH 4/4] Fix semi-colon lint --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3456e458a7b9c..cf97d59490c76 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10296,7 +10296,7 @@ namespace ts { function replaceRecursiveAliasReference(template: Type, target: Type): Type { return mapType(template, t => { if (t.flags & TypeFlags.Intersection) { - return getIntersectionType((t as IntersectionType).types.map(u => replaceRecursiveAliasReference(u, target))) + return getIntersectionType((t as IntersectionType).types.map(u => replaceRecursiveAliasReference(u, target))); } const hasSharedAliasSymbol = t.aliasSymbol !== undefined && t.aliasTypeArguments && t.aliasTypeArguments.length === 1 &&