Skip to content

Commit 7d823ae

Browse files
committed
Merge branch 'main' of https://github.com/microsoft/TypeScript into feat/51086
2 parents 659c141 + aa2781d commit 7d823ae

9 files changed

+131
-4
lines changed

src/compiler/checker.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17609,6 +17609,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1760917609
return getTypeOfSymbol(symbol); // intentionally doesn't use resolved symbol so type is cached as expected on the alias
1761017610
}
1761117611
else {
17612+
const type = tryGetDeclaredTypeOfSymbol(resolvedSymbol); // call this first to ensure typeParameters is populated (if applicable)
17613+
const typeParameters = type && getTypeParametersForTypeAndSymbol(type, resolvedSymbol);
17614+
if (node.typeArguments && typeParameters) {
17615+
addLazyDiagnostic(() => {
17616+
checkTypeArgumentConstraints(node, typeParameters);
17617+
});
17618+
}
1761217619
return getTypeReferenceType(node, resolvedSymbol); // getTypeReferenceType doesn't handle aliases - it must get the resolved symbol
1761317620
}
1761417621
}
@@ -37276,12 +37283,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3727637283
return getEffectiveTypeArguments(node, typeParameters)[index];
3727737284
}
3727837285

37279-
function getEffectiveTypeArguments(node: TypeReferenceNode | ExpressionWithTypeArguments, typeParameters: readonly TypeParameter[]): Type[] {
37286+
function getEffectiveTypeArguments(node: TypeReferenceNode | ExpressionWithTypeArguments | NodeWithTypeArguments, typeParameters: readonly TypeParameter[]): Type[] {
3728037287
return fillMissingTypeArguments(map(node.typeArguments!, getTypeFromTypeNode), typeParameters,
3728137288
getMinTypeArgumentCount(typeParameters), isInJSFile(node));
3728237289
}
3728337290

37284-
function checkTypeArgumentConstraints(node: TypeReferenceNode | ExpressionWithTypeArguments, typeParameters: readonly TypeParameter[]): boolean {
37291+
function checkTypeArgumentConstraints(node: TypeReferenceNode | ExpressionWithTypeArguments | NodeWithTypeArguments, typeParameters: readonly TypeParameter[]): boolean {
3728537292
let typeArguments: Type[] | undefined;
3728637293
let mapper: TypeMapper | undefined;
3728737294
let result = true;
@@ -37302,13 +37309,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3730237309
return result;
3730337310
}
3730437311

37312+
function getTypeParametersForTypeAndSymbol(type: Type, symbol: Symbol) {
37313+
if (!isErrorType(type)) {
37314+
return symbol.flags & SymbolFlags.TypeAlias && getSymbolLinks(symbol).typeParameters ||
37315+
(getObjectFlags(type) & ObjectFlags.Reference ? (type as TypeReference).target.localTypeParameters : undefined);
37316+
}
37317+
return undefined;
37318+
}
37319+
3730537320
function getTypeParametersForTypeReference(node: TypeReferenceNode | ExpressionWithTypeArguments) {
3730637321
const type = getTypeFromTypeReference(node);
3730737322
if (!isErrorType(type)) {
3730837323
const symbol = getNodeLinks(node).resolvedSymbol;
3730937324
if (symbol) {
37310-
return symbol.flags & SymbolFlags.TypeAlias && getSymbolLinks(symbol).typeParameters ||
37311-
(getObjectFlags(type) & ObjectFlags.Reference ? (type as TypeReference).target.localTypeParameters : undefined);
37325+
return getTypeParametersForTypeAndSymbol(type, symbol);
3731237326
}
3731337327
}
3731437328
return undefined;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
tests/cases/compiler/file2.ts(1,37): error TS2344: Type 'T' does not satisfy the constraint 'string'.
2+
3+
4+
==== tests/cases/compiler/file1.ts (0 errors) ====
5+
export type Foo<T extends string> = { foo: T }
6+
7+
==== tests/cases/compiler/file2.ts (1 errors) ====
8+
type Bar<T> = import('./file1').Foo<T>;
9+
~
10+
!!! error TS2344: Type 'T' does not satisfy the constraint 'string'.
11+
!!! related TS2208 tests/cases/compiler/file2.ts:1:10: This type parameter might need an `extends string` constraint.
12+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
=== tests/cases/compiler/file1.ts ===
2+
export type Foo<T extends string> = { foo: T }
3+
>Foo : Symbol(Foo, Decl(file1.ts, 0, 0))
4+
>T : Symbol(T, Decl(file1.ts, 0, 16))
5+
>foo : Symbol(foo, Decl(file1.ts, 0, 37))
6+
>T : Symbol(T, Decl(file1.ts, 0, 16))
7+
8+
=== tests/cases/compiler/file2.ts ===
9+
type Bar<T> = import('./file1').Foo<T>;
10+
>Bar : Symbol(Bar, Decl(file2.ts, 0, 0))
11+
>T : Symbol(T, Decl(file2.ts, 0, 9))
12+
>Foo : Symbol(Foo, Decl(file1.ts, 0, 0))
13+
>T : Symbol(T, Decl(file2.ts, 0, 9))
14+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
=== tests/cases/compiler/file1.ts ===
2+
export type Foo<T extends string> = { foo: T }
3+
>Foo : Foo<T>
4+
>foo : T
5+
6+
=== tests/cases/compiler/file2.ts ===
7+
type Bar<T> = import('./file1').Foo<T>;
8+
>Bar : Bar<T>
9+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
tests/cases/compiler/file2.js(3,36): error TS2344: Type 'T' does not satisfy the constraint 'string'.
2+
3+
4+
==== tests/cases/compiler/file1.js (0 errors) ====
5+
/**
6+
* @template {string} T
7+
* @typedef {{ foo: T }} Foo
8+
*/
9+
10+
export default {};
11+
12+
==== tests/cases/compiler/file2.js (1 errors) ====
13+
/**
14+
* @template T
15+
* @typedef {import('./file1').Foo<T>} Bar
16+
~
17+
!!! error TS2344: Type 'T' does not satisfy the constraint 'string'.
18+
!!! related TS2208 tests/cases/compiler/file2.js:2:14: This type parameter might need an `extends string` constraint.
19+
*/
20+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
=== tests/cases/compiler/file1.js ===
2+
3+
/**
4+
* @template {string} T
5+
* @typedef {{ foo: T }} Foo
6+
*/
7+
8+
export default {};
9+
10+
=== tests/cases/compiler/file2.js ===
11+
12+
/**
13+
* @template T
14+
* @typedef {import('./file1').Foo<T>} Bar
15+
*/
16+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
=== tests/cases/compiler/file1.js ===
2+
/**
3+
* @template {string} T
4+
* @typedef {{ foo: T }} Foo
5+
*/
6+
7+
export default {};
8+
>{} : {}
9+
10+
=== tests/cases/compiler/file2.js ===
11+
12+
/**
13+
* @template T
14+
* @typedef {import('./file1').Foo<T>} Bar
15+
*/
16+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// @noEmit: true
2+
// @filename: file1.ts
3+
export type Foo<T extends string> = { foo: T }
4+
5+
// @noEmit: true
6+
// @filename: file2.ts
7+
type Bar<T> = import('./file1').Foo<T>;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// @allowJs: true
2+
// @checkJs: true
3+
// @noEmit: true
4+
// @filename: file1.js
5+
/**
6+
* @template {string} T
7+
* @typedef {{ foo: T }} Foo
8+
*/
9+
10+
export default {};
11+
12+
// @allowJs: true
13+
// @checkJs: true
14+
// @noEmit: true
15+
// @filename: file2.js
16+
/**
17+
* @template T
18+
* @typedef {import('./file1').Foo<T>} Bar
19+
*/

0 commit comments

Comments
 (0)