Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/microsoft/TypeScript into f…
Browse files Browse the repository at this point in the history
…eat/51086
  • Loading branch information
a-tarasyuk committed Dec 14, 2022
2 parents 659c141 + aa2781d commit 7d823ae
Show file tree
Hide file tree
Showing 9 changed files with 131 additions and 4 deletions.
22 changes: 18 additions & 4 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17609,6 +17609,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return getTypeOfSymbol(symbol); // intentionally doesn't use resolved symbol so type is cached as expected on the alias
}
else {
const type = tryGetDeclaredTypeOfSymbol(resolvedSymbol); // call this first to ensure typeParameters is populated (if applicable)
const typeParameters = type && getTypeParametersForTypeAndSymbol(type, resolvedSymbol);
if (node.typeArguments && typeParameters) {
addLazyDiagnostic(() => {
checkTypeArgumentConstraints(node, typeParameters);
});
}
return getTypeReferenceType(node, resolvedSymbol); // getTypeReferenceType doesn't handle aliases - it must get the resolved symbol
}
}
Expand Down Expand Up @@ -37276,12 +37283,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return getEffectiveTypeArguments(node, typeParameters)[index];
}

function getEffectiveTypeArguments(node: TypeReferenceNode | ExpressionWithTypeArguments, typeParameters: readonly TypeParameter[]): Type[] {
function getEffectiveTypeArguments(node: TypeReferenceNode | ExpressionWithTypeArguments | NodeWithTypeArguments, typeParameters: readonly TypeParameter[]): Type[] {
return fillMissingTypeArguments(map(node.typeArguments!, getTypeFromTypeNode), typeParameters,
getMinTypeArgumentCount(typeParameters), isInJSFile(node));
}

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

function getTypeParametersForTypeAndSymbol(type: Type, symbol: Symbol) {
if (!isErrorType(type)) {
return symbol.flags & SymbolFlags.TypeAlias && getSymbolLinks(symbol).typeParameters ||
(getObjectFlags(type) & ObjectFlags.Reference ? (type as TypeReference).target.localTypeParameters : undefined);
}
return undefined;
}

function getTypeParametersForTypeReference(node: TypeReferenceNode | ExpressionWithTypeArguments) {
const type = getTypeFromTypeReference(node);
if (!isErrorType(type)) {
const symbol = getNodeLinks(node).resolvedSymbol;
if (symbol) {
return symbol.flags & SymbolFlags.TypeAlias && getSymbolLinks(symbol).typeParameters ||
(getObjectFlags(type) & ObjectFlags.Reference ? (type as TypeReference).target.localTypeParameters : undefined);
return getTypeParametersForTypeAndSymbol(type, symbol);
}
}
return undefined;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
tests/cases/compiler/file2.ts(1,37): error TS2344: Type 'T' does not satisfy the constraint 'string'.


==== tests/cases/compiler/file1.ts (0 errors) ====
export type Foo<T extends string> = { foo: T }

==== tests/cases/compiler/file2.ts (1 errors) ====
type Bar<T> = import('./file1').Foo<T>;
~
!!! error TS2344: Type 'T' does not satisfy the constraint 'string'.
!!! related TS2208 tests/cases/compiler/file2.ts:1:10: This type parameter might need an `extends string` constraint.

14 changes: 14 additions & 0 deletions tests/baselines/reference/unmetTypeConstraintInImportCall.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
=== tests/cases/compiler/file1.ts ===
export type Foo<T extends string> = { foo: T }
>Foo : Symbol(Foo, Decl(file1.ts, 0, 0))
>T : Symbol(T, Decl(file1.ts, 0, 16))
>foo : Symbol(foo, Decl(file1.ts, 0, 37))
>T : Symbol(T, Decl(file1.ts, 0, 16))

=== tests/cases/compiler/file2.ts ===
type Bar<T> = import('./file1').Foo<T>;
>Bar : Symbol(Bar, Decl(file2.ts, 0, 0))
>T : Symbol(T, Decl(file2.ts, 0, 9))
>Foo : Symbol(Foo, Decl(file1.ts, 0, 0))
>T : Symbol(T, Decl(file2.ts, 0, 9))

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
=== tests/cases/compiler/file1.ts ===
export type Foo<T extends string> = { foo: T }
>Foo : Foo<T>
>foo : T

=== tests/cases/compiler/file2.ts ===
type Bar<T> = import('./file1').Foo<T>;
>Bar : Bar<T>

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
tests/cases/compiler/file2.js(3,36): error TS2344: Type 'T' does not satisfy the constraint 'string'.


==== tests/cases/compiler/file1.js (0 errors) ====
/**
* @template {string} T
* @typedef {{ foo: T }} Foo
*/

export default {};

==== tests/cases/compiler/file2.js (1 errors) ====
/**
* @template T
* @typedef {import('./file1').Foo<T>} Bar
~
!!! error TS2344: Type 'T' does not satisfy the constraint 'string'.
!!! related TS2208 tests/cases/compiler/file2.js:2:14: This type parameter might need an `extends string` constraint.
*/

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
=== tests/cases/compiler/file1.js ===

/**
* @template {string} T
* @typedef {{ foo: T }} Foo
*/

export default {};

=== tests/cases/compiler/file2.js ===

/**
* @template T
* @typedef {import('./file1').Foo<T>} Bar
*/

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
=== tests/cases/compiler/file1.js ===
/**
* @template {string} T
* @typedef {{ foo: T }} Foo
*/

export default {};
>{} : {}

=== tests/cases/compiler/file2.js ===

/**
* @template T
* @typedef {import('./file1').Foo<T>} Bar
*/

7 changes: 7 additions & 0 deletions tests/cases/compiler/unmetTypeConstraintInImportCall.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// @noEmit: true
// @filename: file1.ts
export type Foo<T extends string> = { foo: T }

// @noEmit: true
// @filename: file2.ts
type Bar<T> = import('./file1').Foo<T>;
19 changes: 19 additions & 0 deletions tests/cases/compiler/unmetTypeConstraintInJSDocImportCall.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// @allowJs: true
// @checkJs: true
// @noEmit: true
// @filename: file1.js
/**
* @template {string} T
* @typedef {{ foo: T }} Foo
*/

export default {};

// @allowJs: true
// @checkJs: true
// @noEmit: true
// @filename: file2.js
/**
* @template T
* @typedef {import('./file1').Foo<T>} Bar
*/

0 comments on commit 7d823ae

Please sign in to comment.