Skip to content

Commit

Permalink
Cherry-pick PR #50691 into release-4.8 (#50743)
Browse files Browse the repository at this point in the history
Component commits:
3644959 Add test case

17f6e57 Revert removal of nonInferrableAnyType

cafebee Rename test

Co-authored-by: Jake Bailey <[email protected]>
  • Loading branch information
TypeScript Bot and jakebailey authored Sep 22, 2022
1 parent 39576e6 commit 2acf3a3
Show file tree
Hide file tree
Showing 5 changed files with 234 additions and 2 deletions.
12 changes: 10 additions & 2 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,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");
Expand Down Expand Up @@ -9540,7 +9541,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
Expand Down Expand Up @@ -22598,7 +22603,10 @@ namespace ts {
//
// This flag is infectious; if we produce Box<never> (where never is silentNeverType), Box<never> 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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//// [inferStringLiteralUnionForBindingElement.ts]
declare function func<T extends string>(arg: { keys: T[] }): { readonly keys: T[]; readonly firstKey: T; };

function func1() {
const { firstKey } = func({keys: ["aa", "bb"]})
const a: "aa" | "bb" = firstKey;

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;
const b: ("aa" | "bb")[] = keys;
}

function func3() {
const x = func({keys: ["aa", "bb"]})
const a: "aa" | "bb" = x.firstKey;
const b: ("aa" | "bb")[] = x.keys;
}


//// [inferStringLiteralUnionForBindingElement.js]
function func1() {
var firstKey = func({ keys: ["aa", "bb"] }).firstKey;
var a = firstKey;
var keys = func({ keys: ["aa", "bb"] }).keys;
var b = keys;
}
function func2() {
var _a = func({ keys: ["aa", "bb"] }), keys = _a.keys, firstKey = _a.firstKey;
var a = firstKey;
var b = keys;
}
function func3() {
var x = func({ keys: ["aa", "bb"] });
var a = x.firstKey;
var b = x.keys;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
=== tests/cases/compiler/inferStringLiteralUnionForBindingElement.ts ===
declare function func<T extends string>(arg: { keys: T[] }): { readonly keys: T[]; readonly firstKey: T; };
>func : Symbol(func, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 0))
>T : Symbol(T, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 22))
>arg : Symbol(arg, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 40))
>keys : Symbol(keys, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 46))
>T : Symbol(T, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 22))
>keys : Symbol(keys, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 62))
>T : Symbol(T, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 22))
>firstKey : Symbol(firstKey, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 82))
>T : Symbol(T, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 22))

function func1() {
>func1 : Symbol(func1, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 107))

const { firstKey } = func({keys: ["aa", "bb"]})
>firstKey : Symbol(firstKey, Decl(inferStringLiteralUnionForBindingElement.ts, 3, 11))
>func : Symbol(func, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 0))
>keys : Symbol(keys, Decl(inferStringLiteralUnionForBindingElement.ts, 3, 31))

const a: "aa" | "bb" = firstKey;
>a : Symbol(a, Decl(inferStringLiteralUnionForBindingElement.ts, 4, 9))
>firstKey : Symbol(firstKey, Decl(inferStringLiteralUnionForBindingElement.ts, 3, 11))

const { keys } = func({keys: ["aa", "bb"]})
>keys : Symbol(keys, Decl(inferStringLiteralUnionForBindingElement.ts, 6, 11))
>func : Symbol(func, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 0))
>keys : Symbol(keys, Decl(inferStringLiteralUnionForBindingElement.ts, 6, 27))

const b: ("aa" | "bb")[] = keys;
>b : Symbol(b, Decl(inferStringLiteralUnionForBindingElement.ts, 7, 9))
>keys : Symbol(keys, Decl(inferStringLiteralUnionForBindingElement.ts, 6, 11))
}

function func2() {
>func2 : Symbol(func2, Decl(inferStringLiteralUnionForBindingElement.ts, 8, 1))

const { keys, firstKey } = func({keys: ["aa", "bb"]})
>keys : Symbol(keys, Decl(inferStringLiteralUnionForBindingElement.ts, 11, 11))
>firstKey : Symbol(firstKey, Decl(inferStringLiteralUnionForBindingElement.ts, 11, 17))
>func : Symbol(func, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 0))
>keys : Symbol(keys, Decl(inferStringLiteralUnionForBindingElement.ts, 11, 37))

const a: "aa" | "bb" = firstKey;
>a : Symbol(a, Decl(inferStringLiteralUnionForBindingElement.ts, 12, 9))
>firstKey : Symbol(firstKey, Decl(inferStringLiteralUnionForBindingElement.ts, 11, 17))

const b: ("aa" | "bb")[] = keys;
>b : Symbol(b, Decl(inferStringLiteralUnionForBindingElement.ts, 13, 9))
>keys : Symbol(keys, Decl(inferStringLiteralUnionForBindingElement.ts, 11, 11))
}

function func3() {
>func3 : Symbol(func3, Decl(inferStringLiteralUnionForBindingElement.ts, 14, 1))

const x = func({keys: ["aa", "bb"]})
>x : Symbol(x, Decl(inferStringLiteralUnionForBindingElement.ts, 17, 9))
>func : Symbol(func, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 0))
>keys : Symbol(keys, Decl(inferStringLiteralUnionForBindingElement.ts, 17, 20))

const a: "aa" | "bb" = x.firstKey;
>a : Symbol(a, Decl(inferStringLiteralUnionForBindingElement.ts, 18, 9))
>x.firstKey : Symbol(firstKey, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 82))
>x : Symbol(x, Decl(inferStringLiteralUnionForBindingElement.ts, 17, 9))
>firstKey : Symbol(firstKey, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 82))

const b: ("aa" | "bb")[] = x.keys;
>b : Symbol(b, Decl(inferStringLiteralUnionForBindingElement.ts, 19, 9))
>x.keys : Symbol(keys, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 62))
>x : Symbol(x, Decl(inferStringLiteralUnionForBindingElement.ts, 17, 9))
>keys : Symbol(keys, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 62))
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
=== tests/cases/compiler/inferStringLiteralUnionForBindingElement.ts ===
declare function func<T extends string>(arg: { keys: T[] }): { readonly keys: T[]; readonly firstKey: T; };
>func : <T extends string>(arg: { keys: T[];}) => { readonly keys: T[]; readonly firstKey: T;}
>arg : { keys: T[]; }
>keys : T[]
>keys : T[]
>firstKey : T

function func1() {
>func1 : () => void

const { firstKey } = func({keys: ["aa", "bb"]})
>firstKey : "aa" | "bb"
>func({keys: ["aa", "bb"]}) : { readonly keys: ("aa" | "bb")[]; readonly firstKey: "aa" | "bb"; }
>func : <T extends string>(arg: { keys: T[]; }) => { readonly keys: T[]; readonly firstKey: T; }
>{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 : "aa" | "bb"

const { keys } = func({keys: ["aa", "bb"]})
>keys : ("aa" | "bb")[]
>func({keys: ["aa", "bb"]}) : { readonly keys: ("aa" | "bb")[]; readonly firstKey: "aa" | "bb"; }
>func : <T extends string>(arg: { keys: T[]; }) => { readonly keys: T[]; readonly firstKey: T; }
>{keys: ["aa", "bb"]} : { keys: ("aa" | "bb")[]; }
>keys : ("aa" | "bb")[]
>["aa", "bb"] : ("aa" | "bb")[]
>"aa" : "aa"
>"bb" : "bb"

const b: ("aa" | "bb")[] = keys;
>b : ("aa" | "bb")[]
>keys : ("aa" | "bb")[]
}

function func2() {
>func2 : () => void

const { keys, firstKey } = func({keys: ["aa", "bb"]})
>keys : ("aa" | "bb")[]
>firstKey : "aa" | "bb"
>func({keys: ["aa", "bb"]}) : { readonly keys: ("aa" | "bb")[]; readonly firstKey: "aa" | "bb"; }
>func : <T extends string>(arg: { keys: T[]; }) => { readonly keys: T[]; readonly firstKey: T; }
>{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 : "aa" | "bb"

const b: ("aa" | "bb")[] = keys;
>b : ("aa" | "bb")[]
>keys : ("aa" | "bb")[]
}

function func3() {
>func3 : () => void

const x = func({keys: ["aa", "bb"]})
>x : { readonly keys: ("aa" | "bb")[]; readonly firstKey: "aa" | "bb"; }
>func({keys: ["aa", "bb"]}) : { readonly keys: ("aa" | "bb")[]; readonly firstKey: "aa" | "bb"; }
>func : <T extends string>(arg: { keys: T[]; }) => { readonly keys: T[]; readonly firstKey: T; }
>{keys: ["aa", "bb"]} : { keys: ("aa" | "bb")[]; }
>keys : ("aa" | "bb")[]
>["aa", "bb"] : ("aa" | "bb")[]
>"aa" : "aa"
>"bb" : "bb"

const a: "aa" | "bb" = x.firstKey;
>a : "aa" | "bb"
>x.firstKey : "aa" | "bb"
>x : { readonly keys: ("aa" | "bb")[]; readonly firstKey: "aa" | "bb"; }
>firstKey : "aa" | "bb"

const b: ("aa" | "bb")[] = x.keys;
>b : ("aa" | "bb")[]
>x.keys : ("aa" | "bb")[]
>x : { readonly keys: ("aa" | "bb")[]; readonly firstKey: "aa" | "bb"; }
>keys : ("aa" | "bb")[]
}

21 changes: 21 additions & 0 deletions tests/cases/compiler/inferStringLiteralUnionForBindingElement.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
declare function func<T extends string>(arg: { keys: T[] }): { readonly keys: T[]; readonly firstKey: T; };

function func1() {
const { firstKey } = func({keys: ["aa", "bb"]})
const a: "aa" | "bb" = firstKey;

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;
const b: ("aa" | "bb")[] = keys;
}

function func3() {
const x = func({keys: ["aa", "bb"]})
const a: "aa" | "bb" = x.firstKey;
const b: ("aa" | "bb")[] = x.keys;
}

0 comments on commit 2acf3a3

Please sign in to comment.