Skip to content

Commit 87b09f8

Browse files
committed
Merge branch 'main' of https://github.com/microsoft/TypeScript into fix(52604)
2 parents 54456cc + f647b11 commit 87b09f8

15 files changed

+661
-343
lines changed

.github/workflows/close-issues.yml

+6-2
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ jobs:
3131
3232
close_issues() {
3333
echo "Closing issues marked as '$1'."
34-
for issue in $(gh issue list --label "$1" --repo ${{ github.repository }} --state open --search "updated:<$DATE" --json number --jq '.[].number'); do
34+
for issue in $(gh issue list --limit 100 --label "$1" --repo ${{ github.repository }} --state open --search "updated:<$DATE" --json number --jq '.[].number'); do
3535
echo "Closing https://github.com/${{ github.repository }}/issues/$issue"
36-
gh issue close $issue --repo ${{ github.repository }} --reason "not planned" --comment "This issue has been marked as '$1' and has seen no recent activity. It has been automatically closed for house-keeping purposes."
36+
gh issue close $issue --repo ${{ github.repository }} --reason "not planned" --comment "This issue has been marked as \"$1\" and has seen no recent activity. It has been automatically closed for house-keeping purposes."
3737
done
3838
}
3939
@@ -43,3 +43,7 @@ jobs:
4343
close_issues "External"
4444
close_issues "Working as Intended"
4545
close_issues "Question"
46+
close_issues "Out of Scope"
47+
close_issues "Declined"
48+
close_issues "Won't Fix"
49+
close_issues "Too Complex"

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,4 @@ TEST-results.xml
6262
package-lock.json
6363
.eslintcache
6464
*v8.log
65-
lib/
65+
/lib/

package-lock.json

+342-322
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/compiler/checker.ts

+32-18
Original file line numberDiff line numberDiff line change
@@ -1828,14 +1828,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
18281828
};
18291829

18301830
function runWithoutResolvedSignatureCaching<T>(node: Node | undefined, fn: () => T): T {
1831-
const containingCall = findAncestor(node, isCallLikeExpression);
1832-
const containingCallResolvedSignature = containingCall && getNodeLinks(containingCall).resolvedSignature;
1833-
if (containingCall) {
1834-
getNodeLinks(containingCall).resolvedSignature = undefined;
1831+
const cachedSignatures = [];
1832+
while (node) {
1833+
if (isCallLikeExpression(node)) {
1834+
const nodeLinks = getNodeLinks(node);
1835+
const resolvedSignature = nodeLinks.resolvedSignature;
1836+
cachedSignatures.push([nodeLinks, resolvedSignature] as const);
1837+
nodeLinks.resolvedSignature = undefined;
1838+
}
1839+
node = node.parent;
18351840
}
18361841
const result = fn();
1837-
if (containingCall) {
1838-
getNodeLinks(containingCall).resolvedSignature = containingCallResolvedSignature;
1842+
for (const [nodeLinks, resolvedSignature] of cachedSignatures) {
1843+
nodeLinks.resolvedSignature = resolvedSignature;
18391844
}
18401845
return result;
18411846
}
@@ -10165,11 +10170,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1016510170
return prop ? getTypeOfSymbol(prop) : undefined;
1016610171
}
1016710172

10168-
function getTypeOfPropertyOrIndexSignature(type: Type, name: __String, addOptionalityToIndex: boolean): Type {
10173+
function getTypeOfPropertyOrIndexSignature(type: Type, name: __String): Type {
10174+
return getTypeOfPropertyOfType(type, name) || getApplicableIndexInfoForName(type, name)?.type || unknownType;
10175+
}
10176+
10177+
/**
10178+
* Similar to `getTypeOfPropertyOrIndexSignature`,
10179+
* but returns `undefined` if there is no matching property or index signature,
10180+
* and adds optionality to index signature types.
10181+
*/
10182+
function getTypeOfPropertyOrIndexSignatureOfType(type: Type, name: __String): Type | undefined {
1016910183
let propType;
1017010184
return getTypeOfPropertyOfType(type, name) ||
10171-
(propType = getApplicableIndexInfoForName(type, name)?.type) && addOptionality(propType, /*isProperty*/ true, addOptionalityToIndex) ||
10172-
unknownType;
10185+
(propType = getApplicableIndexInfoForName(type, name)?.type) &&
10186+
addOptionality(propType, /*isProperty*/ true, /*isOptional*/ true);
1017310187
}
1017410188

1017510189
function isTypeAny(type: Type | undefined) {
@@ -13538,14 +13552,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1353813552
return hasNonCircularBaseConstraint(typeParameter) ? getConstraintFromTypeParameter(typeParameter) : undefined;
1353913553
}
1354013554

13541-
function isConstTypeVariable(type: Type | undefined): boolean {
13542-
return !!(type && (
13555+
function isConstTypeVariable(type: Type | undefined, depth = 0): boolean {
13556+
return depth < 5 && !!(type && (
1354313557
type.flags & TypeFlags.TypeParameter && some((type as TypeParameter).symbol?.declarations, d => hasSyntacticModifier(d, ModifierFlags.Const)) ||
13544-
type.flags & TypeFlags.Union && some((type as UnionType).types, isConstTypeVariable) ||
13545-
type.flags & TypeFlags.IndexedAccess && isConstTypeVariable((type as IndexedAccessType).objectType) ||
13546-
type.flags & TypeFlags.Conditional && isConstTypeVariable(getConstraintOfConditionalType(type as ConditionalType)) ||
13547-
type.flags & TypeFlags.Substitution && isConstTypeVariable((type as SubstitutionType).baseType) ||
13548-
isGenericTupleType(type) && findIndex(getElementTypes(type), (t, i) => !!(type.target.elementFlags[i] & ElementFlags.Variadic) && isConstTypeVariable(t)) >= 0));
13558+
type.flags & TypeFlags.Union && some((type as UnionType).types, t => isConstTypeVariable(t, depth)) ||
13559+
type.flags & TypeFlags.IndexedAccess && isConstTypeVariable((type as IndexedAccessType).objectType, depth + 1) ||
13560+
type.flags & TypeFlags.Conditional && isConstTypeVariable(getConstraintOfConditionalType(type as ConditionalType), depth + 1) ||
13561+
type.flags & TypeFlags.Substitution && isConstTypeVariable((type as SubstitutionType).baseType, depth) ||
13562+
isGenericTupleType(type) && findIndex(getElementTypes(type), (t, i) => !!(type.target.elementFlags[i] & ElementFlags.Variadic) && isConstTypeVariable(t, depth)) >= 0));
1354913563
}
1355013564

1355113565
function getConstraintOfIndexedAccess(type: IndexedAccessType) {
@@ -22703,7 +22717,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2270322717
let matched = false;
2270422718
for (let i = 0; i < types.length; i++) {
2270522719
if (include[i]) {
22706-
const targetType = getTypeOfPropertyOrIndexSignature(types[i], propertyName, /*addOptionalityToIndex*/ true);
22720+
const targetType = getTypeOfPropertyOrIndexSignatureOfType(types[i], propertyName);
2270722721
if (targetType && related(getDiscriminatingType(), targetType)) {
2270822722
matched = true;
2270922723
}
@@ -27016,7 +27030,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2701627030
propType = removeNullable && optionalChain ? getOptionalType(propType) : propType;
2701727031
const narrowedPropType = narrowType(propType);
2701827032
return filterType(type, t => {
27019-
const discriminantType = getTypeOfPropertyOrIndexSignature(t, propName, /*addOptionalityToIndex*/ false);
27033+
const discriminantType = getTypeOfPropertyOrIndexSignature(t, propName);
2702027034
return !(discriminantType.flags & TypeFlags.Never) && !(narrowedPropType.flags & TypeFlags.Never) && areTypesComparable(narrowedPropType, discriminantType);
2702127035
});
2702227036
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
circularBaseConstraint.ts(14,8): error TS2304: Cannot find name 'a'.
2+
3+
4+
==== circularBaseConstraint.ts (1 errors) ====
5+
// Repro from #54610
6+
7+
type A<T> = T;
8+
9+
type B<T> = T extends any[]
10+
? never
11+
: A<T> extends infer key
12+
? key extends keyof T
13+
? B<T[key]>
14+
: never
15+
: never;
16+
17+
function foo<T>() {
18+
`${a}` as B<T>;
19+
~
20+
!!! error TS2304: Cannot find name 'a'.
21+
}
22+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//// [tests/cases/compiler/circularBaseConstraint.ts] ////
2+
3+
=== circularBaseConstraint.ts ===
4+
// Repro from #54610
5+
6+
type A<T> = T;
7+
>A : Symbol(A, Decl(circularBaseConstraint.ts, 0, 0))
8+
>T : Symbol(T, Decl(circularBaseConstraint.ts, 2, 7))
9+
>T : Symbol(T, Decl(circularBaseConstraint.ts, 2, 7))
10+
11+
type B<T> = T extends any[]
12+
>B : Symbol(B, Decl(circularBaseConstraint.ts, 2, 14))
13+
>T : Symbol(T, Decl(circularBaseConstraint.ts, 4, 7))
14+
>T : Symbol(T, Decl(circularBaseConstraint.ts, 4, 7))
15+
16+
? never
17+
: A<T> extends infer key
18+
>A : Symbol(A, Decl(circularBaseConstraint.ts, 0, 0))
19+
>T : Symbol(T, Decl(circularBaseConstraint.ts, 4, 7))
20+
>key : Symbol(key, Decl(circularBaseConstraint.ts, 6, 24))
21+
22+
? key extends keyof T
23+
>key : Symbol(key, Decl(circularBaseConstraint.ts, 6, 24))
24+
>T : Symbol(T, Decl(circularBaseConstraint.ts, 4, 7))
25+
26+
? B<T[key]>
27+
>B : Symbol(B, Decl(circularBaseConstraint.ts, 2, 14))
28+
>T : Symbol(T, Decl(circularBaseConstraint.ts, 4, 7))
29+
>key : Symbol(key, Decl(circularBaseConstraint.ts, 6, 24))
30+
31+
: never
32+
: never;
33+
34+
function foo<T>() {
35+
>foo : Symbol(foo, Decl(circularBaseConstraint.ts, 10, 12))
36+
>T : Symbol(T, Decl(circularBaseConstraint.ts, 12, 13))
37+
38+
`${a}` as B<T>;
39+
>B : Symbol(B, Decl(circularBaseConstraint.ts, 2, 14))
40+
>T : Symbol(T, Decl(circularBaseConstraint.ts, 12, 13))
41+
}
42+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//// [tests/cases/compiler/circularBaseConstraint.ts] ////
2+
3+
=== circularBaseConstraint.ts ===
4+
// Repro from #54610
5+
6+
type A<T> = T;
7+
>A : T
8+
9+
type B<T> = T extends any[]
10+
>B : B<T>
11+
12+
? never
13+
: A<T> extends infer key
14+
? key extends keyof T
15+
? B<T[key]>
16+
: never
17+
: never;
18+
19+
function foo<T>() {
20+
>foo : <T>() => void
21+
22+
`${a}` as B<T>;
23+
>`${a}` as B<T> : B<T>
24+
>`${a}` : string
25+
>a : any
26+
}
27+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
discriminateWithMissingProperty.ts(12,5): error TS2345: Argument of type '{ mode: "numeric"; data: Uint8Array; }' is not assignable to parameter of type 'Arg'.
2+
Types of property 'data' are incompatible.
3+
Type 'Uint8Array' is not assignable to type 'number'.
4+
5+
6+
==== discriminateWithMissingProperty.ts (1 errors) ====
7+
type Arg = {
8+
mode: "numeric",
9+
data: number,
10+
} | {
11+
mode: "alphabetic",
12+
data: string,
13+
} | {
14+
data: string | Uint8Array;
15+
}
16+
17+
declare function foo(arg: Arg): void;
18+
foo({ mode: "numeric", data: new Uint8Array([30]) }); // Should error
19+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20+
!!! error TS2345: Argument of type '{ mode: "numeric"; data: Uint8Array; }' is not assignable to parameter of type 'Arg'.
21+
!!! error TS2345: Types of property 'data' are incompatible.
22+
!!! error TS2345: Type 'Uint8Array' is not assignable to type 'number'.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//// [tests/cases/compiler/discriminateWithMissingProperty.ts] ////
2+
3+
=== discriminateWithMissingProperty.ts ===
4+
type Arg = {
5+
>Arg : Symbol(Arg, Decl(discriminateWithMissingProperty.ts, 0, 0))
6+
7+
mode: "numeric",
8+
>mode : Symbol(mode, Decl(discriminateWithMissingProperty.ts, 0, 12))
9+
10+
data: number,
11+
>data : Symbol(data, Decl(discriminateWithMissingProperty.ts, 1, 20))
12+
13+
} | {
14+
mode: "alphabetic",
15+
>mode : Symbol(mode, Decl(discriminateWithMissingProperty.ts, 3, 5))
16+
17+
data: string,
18+
>data : Symbol(data, Decl(discriminateWithMissingProperty.ts, 4, 23))
19+
20+
} | {
21+
data: string | Uint8Array;
22+
>data : Symbol(data, Decl(discriminateWithMissingProperty.ts, 6, 5))
23+
>Uint8Array : Symbol(Uint8Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
24+
}
25+
26+
declare function foo(arg: Arg): void;
27+
>foo : Symbol(foo, Decl(discriminateWithMissingProperty.ts, 8, 1))
28+
>arg : Symbol(arg, Decl(discriminateWithMissingProperty.ts, 10, 21))
29+
>Arg : Symbol(Arg, Decl(discriminateWithMissingProperty.ts, 0, 0))
30+
31+
foo({ mode: "numeric", data: new Uint8Array([30]) }); // Should error
32+
>foo : Symbol(foo, Decl(discriminateWithMissingProperty.ts, 8, 1))
33+
>mode : Symbol(mode, Decl(discriminateWithMissingProperty.ts, 11, 5))
34+
>data : Symbol(data, Decl(discriminateWithMissingProperty.ts, 11, 22))
35+
>Uint8Array : Symbol(Uint8Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
36+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//// [tests/cases/compiler/discriminateWithMissingProperty.ts] ////
2+
3+
=== discriminateWithMissingProperty.ts ===
4+
type Arg = {
5+
>Arg : { mode: "numeric"; data: number; } | { mode: "alphabetic"; data: string; } | { data: string | Uint8Array; }
6+
7+
mode: "numeric",
8+
>mode : "numeric"
9+
10+
data: number,
11+
>data : number
12+
13+
} | {
14+
mode: "alphabetic",
15+
>mode : "alphabetic"
16+
17+
data: string,
18+
>data : string
19+
20+
} | {
21+
data: string | Uint8Array;
22+
>data : string | Uint8Array
23+
}
24+
25+
declare function foo(arg: Arg): void;
26+
>foo : (arg: Arg) => void
27+
>arg : Arg
28+
29+
foo({ mode: "numeric", data: new Uint8Array([30]) }); // Should error
30+
>foo({ mode: "numeric", data: new Uint8Array([30]) }) : void
31+
>foo : (arg: Arg) => void
32+
>{ mode: "numeric", data: new Uint8Array([30]) } : { mode: "numeric"; data: Uint8Array; }
33+
>mode : "numeric"
34+
>"numeric" : "numeric"
35+
>data : Uint8Array
36+
>new Uint8Array([30]) : Uint8Array
37+
>Uint8Array : Uint8ArrayConstructor
38+
>[30] : number[]
39+
>30 : 30
40+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// @strict: true
2+
// @noEmit: true
3+
4+
// Repro from #54610
5+
6+
type A<T> = T;
7+
8+
type B<T> = T extends any[]
9+
? never
10+
: A<T> extends infer key
11+
? key extends keyof T
12+
? B<T[key]>
13+
: never
14+
: never;
15+
16+
function foo<T>() {
17+
`${a}` as B<T>;
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// @strict: true
2+
// @noEmit: true
3+
4+
type Arg = {
5+
mode: "numeric",
6+
data: number,
7+
} | {
8+
mode: "alphabetic",
9+
data: string,
10+
} | {
11+
data: string | Uint8Array;
12+
}
13+
14+
declare function foo(arg: Arg): void;
15+
foo({ mode: "numeric", data: new Uint8Array([30]) }); // Should error
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/// <reference path="fourslash.ts" />
2+
// @strict: true
3+
////
4+
//// declare function func<
5+
//// const T extends 'a' | 'b' | undefined = undefined,
6+
//// >(arg?: T): string;
7+
////
8+
//// func('/*1*/');
9+
10+
verify.completions({ marker: ["1"], exact: [`a`, `b`] });
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/// <reference path="fourslash.ts" />
2+
// @strict: true
3+
////
4+
//// interface Func {
5+
//// <Key extends "a" | "b">(
6+
//// ...args:
7+
//// | [key: Key, options?: any]
8+
//// | [key: Key, defaultValue: string, options?: any]
9+
//// ): string;
10+
//// }
11+
////
12+
//// declare const func: Func;
13+
////
14+
//// func("/*1*/");
15+
16+
verify.completions({ marker: ["1"], exact: [`a`, `b`] });

0 commit comments

Comments
 (0)