diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6da3c9e760c..43bd84675cc 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -791,6 +791,7 @@ namespace ts { const wildcardType = createIntrinsicType(TypeFlags.Any, "any"); const errorType = createIntrinsicType(TypeFlags.Any, "error"); const unresolvedType = createIntrinsicType(TypeFlags.Any, "unresolved"); + const nonInferrableAnyType = createIntrinsicType(TypeFlags.Any, "any", ObjectFlags.ContainsWideningType); const intrinsicMarkerType = createIntrinsicType(TypeFlags.Any, "intrinsic"); const unknownType = createIntrinsicType(TypeFlags.Unknown, "unknown"); const nonNullUnknownType = createIntrinsicType(TypeFlags.Unknown, "unknown"); @@ -9560,7 +9561,11 @@ namespace ts { if (reportErrors && !declarationBelongsToPrivateAmbientMember(element)) { reportImplicitAny(element, anyType); } - return anyType; + // When we're including the pattern in the type (an indication we're obtaining a contextual type), we + // use a non-inferrable any type. Inference will never directly infer this type, but it is possible + // to infer a type that contains it, e.g. for a binding pattern like [foo] or { foo }. In such cases, + // widening of the binding pattern type substitutes a regular any for the non-inferrable any. + return includePatternInType ? nonInferrableAnyType : anyType; } // Return the type implied by an object binding pattern @@ -22631,7 +22636,10 @@ namespace ts { // // This flag is infectious; if we produce Box (where never is silentNeverType), Box is // also non-inferrable. - if (getObjectFlags(source) & ObjectFlags.NonInferrableType) { + // + // As a special case, also ignore nonInferrableAnyType, which is a special form of the any type + // used as a stand-in for binding elements when they are being inferred. + if (getObjectFlags(source) & ObjectFlags.NonInferrableType || source === nonInferrableAnyType) { return; } if (!inference.isFixed) { diff --git a/tests/baselines/reference/issue50680.errors.txt b/tests/baselines/reference/issue50680.errors.txt deleted file mode 100644 index 241abea1b35..00000000000 --- a/tests/baselines/reference/issue50680.errors.txt +++ /dev/null @@ -1,36 +0,0 @@ -tests/cases/compiler/issue50680.ts(5,11): error TS2322: Type 'string' is not assignable to type '"aa" | "bb"'. -tests/cases/compiler/issue50680.ts(13,11): error TS2322: Type 'string' is not assignable to type '"aa" | "bb"'. -tests/cases/compiler/issue50680.ts(14,11): error TS2322: Type 'string[]' is not assignable to type '("aa" | "bb")[]'. - Type 'string' is not assignable to type '"aa" | "bb"'. - - -==== tests/cases/compiler/issue50680.ts (3 errors) ==== - declare function func(arg: { keys: T[] }): { readonly keys: T[]; readonly firstKey: T; }; - - function func1() { - const { firstKey } = func({keys: ["aa", "bb"]}) - const a: "aa" | "bb" = firstKey; - ~ -!!! error TS2322: Type 'string' is not assignable to type '"aa" | "bb"'. - - const { keys } = func({keys: ["aa", "bb"]}) - const b: ("aa" | "bb")[] = keys; - } - - function func2() { - const { keys, firstKey } = func({keys: ["aa", "bb"]}) - const a: "aa" | "bb" = firstKey; - ~ -!!! error TS2322: Type 'string' is not assignable to type '"aa" | "bb"'. - const b: ("aa" | "bb")[] = keys; - ~ -!!! error TS2322: Type 'string[]' is not assignable to type '("aa" | "bb")[]'. -!!! error TS2322: Type 'string' is not assignable to type '"aa" | "bb"'. - } - - function func3() { - const x = func({keys: ["aa", "bb"]}) - const a: "aa" | "bb" = x.firstKey; - const b: ("aa" | "bb")[] = x.keys; - } - \ No newline at end of file diff --git a/tests/baselines/reference/issue50680.types b/tests/baselines/reference/issue50680.types index 1ad1f004f58..860ee69a1d0 100644 --- a/tests/baselines/reference/issue50680.types +++ b/tests/baselines/reference/issue50680.types @@ -10,18 +10,18 @@ function func1() { >func1 : () => void const { firstKey } = func({keys: ["aa", "bb"]}) ->firstKey : string ->func({keys: ["aa", "bb"]}) : { readonly keys: string[]; readonly firstKey: string; } +>firstKey : "aa" | "bb" +>func({keys: ["aa", "bb"]}) : { readonly keys: ("aa" | "bb")[]; readonly firstKey: "aa" | "bb"; } >func : (arg: { keys: T[]; }) => { readonly keys: T[]; readonly firstKey: T; } ->{keys: ["aa", "bb"]} : { keys: string[]; } ->keys : string[] ->["aa", "bb"] : string[] +>{keys: ["aa", "bb"]} : { keys: ("aa" | "bb")[]; } +>keys : ("aa" | "bb")[] +>["aa", "bb"] : ("aa" | "bb")[] >"aa" : "aa" >"bb" : "bb" const a: "aa" | "bb" = firstKey; >a : "aa" | "bb" ->firstKey : string +>firstKey : "aa" | "bb" const { keys } = func({keys: ["aa", "bb"]}) >keys : ("aa" | "bb")[] @@ -42,23 +42,23 @@ function func2() { >func2 : () => void const { keys, firstKey } = func({keys: ["aa", "bb"]}) ->keys : string[] ->firstKey : string ->func({keys: ["aa", "bb"]}) : { readonly keys: string[]; readonly firstKey: string; } +>keys : ("aa" | "bb")[] +>firstKey : "aa" | "bb" +>func({keys: ["aa", "bb"]}) : { readonly keys: ("aa" | "bb")[]; readonly firstKey: "aa" | "bb"; } >func : (arg: { keys: T[]; }) => { readonly keys: T[]; readonly firstKey: T; } ->{keys: ["aa", "bb"]} : { keys: string[]; } ->keys : string[] ->["aa", "bb"] : string[] +>{keys: ["aa", "bb"]} : { keys: ("aa" | "bb")[]; } +>keys : ("aa" | "bb")[] +>["aa", "bb"] : ("aa" | "bb")[] >"aa" : "aa" >"bb" : "bb" const a: "aa" | "bb" = firstKey; >a : "aa" | "bb" ->firstKey : string +>firstKey : "aa" | "bb" const b: ("aa" | "bb")[] = keys; >b : ("aa" | "bb")[] ->keys : string[] +>keys : ("aa" | "bb")[] } function func3() {