diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bf7d17a951f72..1997dc946be64 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12199,9 +12199,20 @@ namespace ts { function getBaseSignature(signature: Signature) { const typeParameters = signature.typeParameters; if (typeParameters) { + if (signature.baseSignatureCache) { + return signature.baseSignatureCache; + } const typeEraser = createTypeEraser(typeParameters); - const baseConstraints = map(typeParameters, tp => instantiateType(getBaseConstraintOfType(tp), typeEraser) || unknownType); - return instantiateSignature(signature, createTypeMapper(typeParameters, baseConstraints), /*eraseTypeParameters*/ true); + const baseConstraintMapper = createTypeMapper(typeParameters, map(typeParameters, tp => getConstraintOfTypeParameter(tp) || unknownType)); + let baseConstraints: readonly Type[] = map(typeParameters, tp => instantiateType(tp, baseConstraintMapper) || unknownType); + // Run N type params thru the immediate constraint mapper up to N times + // This way any noncircular interdependent type parameters are definitely resolved to their external dependencies + for (let i = 0; i < typeParameters.length - 1; i++) { + baseConstraints = instantiateTypes(baseConstraints, baseConstraintMapper); + } + // and then apply a type eraser to remove any remaining circularly dependent type parameters + baseConstraints = instantiateTypes(baseConstraints, typeEraser); + return signature.baseSignatureCache = instantiateSignature(signature, createTypeMapper(typeParameters, baseConstraints), /*eraseTypeParameters*/ true); } return signature; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 3585ff50a8f3b..ad8f560a0d7a8 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5552,6 +5552,8 @@ namespace ts { /* @internal */ canonicalSignatureCache?: Signature; // Canonical version of signature (deferred) /* @internal */ + baseSignatureCache?: Signature; // Base version of signature (deferred) + /* @internal */ optionalCallSignatureCache?: { inner?: Signature, outer?: Signature }; // Optional chained call version of signature (deferred) /* @internal */ isolatedSignatureType?: ObjectType; // A manufactured type that just contains the signature for purposes of signature comparison diff --git a/tests/baselines/reference/conditionalTypeGenericInSignatureTypeParameterConstraint.js b/tests/baselines/reference/conditionalTypeGenericInSignatureTypeParameterConstraint.js new file mode 100644 index 0000000000000..0e8bb8e7f372e --- /dev/null +++ b/tests/baselines/reference/conditionalTypeGenericInSignatureTypeParameterConstraint.js @@ -0,0 +1,7 @@ +//// [conditionalTypeGenericInSignatureTypeParameterConstraint.ts] +// should be x +type H_inline1 = (() => o) extends (() => infer o) ? o : never; + +type Result = H_inline1; // should be `string` + +//// [conditionalTypeGenericInSignatureTypeParameterConstraint.js] diff --git a/tests/baselines/reference/conditionalTypeGenericInSignatureTypeParameterConstraint.symbols b/tests/baselines/reference/conditionalTypeGenericInSignatureTypeParameterConstraint.symbols new file mode 100644 index 0000000000000..9d53c7de537e5 --- /dev/null +++ b/tests/baselines/reference/conditionalTypeGenericInSignatureTypeParameterConstraint.symbols @@ -0,0 +1,15 @@ +=== tests/cases/compiler/conditionalTypeGenericInSignatureTypeParameterConstraint.ts === +// should be x +type H_inline1 = (() => o) extends (() => infer o) ? o : never; +>H_inline1 : Symbol(H_inline1, Decl(conditionalTypeGenericInSignatureTypeParameterConstraint.ts, 0, 0)) +>x : Symbol(x, Decl(conditionalTypeGenericInSignatureTypeParameterConstraint.ts, 1, 15)) +>o : Symbol(o, Decl(conditionalTypeGenericInSignatureTypeParameterConstraint.ts, 1, 22)) +>x : Symbol(x, Decl(conditionalTypeGenericInSignatureTypeParameterConstraint.ts, 1, 15)) +>o : Symbol(o, Decl(conditionalTypeGenericInSignatureTypeParameterConstraint.ts, 1, 22)) +>o : Symbol(o, Decl(conditionalTypeGenericInSignatureTypeParameterConstraint.ts, 1, 63)) +>o : Symbol(o, Decl(conditionalTypeGenericInSignatureTypeParameterConstraint.ts, 1, 63)) + +type Result = H_inline1; // should be `string` +>Result : Symbol(Result, Decl(conditionalTypeGenericInSignatureTypeParameterConstraint.ts, 1, 79)) +>H_inline1 : Symbol(H_inline1, Decl(conditionalTypeGenericInSignatureTypeParameterConstraint.ts, 0, 0)) + diff --git a/tests/baselines/reference/conditionalTypeGenericInSignatureTypeParameterConstraint.types b/tests/baselines/reference/conditionalTypeGenericInSignatureTypeParameterConstraint.types new file mode 100644 index 0000000000000..6da7d02ad9afd --- /dev/null +++ b/tests/baselines/reference/conditionalTypeGenericInSignatureTypeParameterConstraint.types @@ -0,0 +1,8 @@ +=== tests/cases/compiler/conditionalTypeGenericInSignatureTypeParameterConstraint.ts === +// should be x +type H_inline1 = (() => o) extends (() => infer o) ? o : never; +>H_inline1 : x + +type Result = H_inline1; // should be `string` +>Result : string + diff --git a/tests/cases/compiler/conditionalTypeGenericInSignatureTypeParameterConstraint.ts b/tests/cases/compiler/conditionalTypeGenericInSignatureTypeParameterConstraint.ts new file mode 100644 index 0000000000000..b4f8c3507f5aa --- /dev/null +++ b/tests/cases/compiler/conditionalTypeGenericInSignatureTypeParameterConstraint.ts @@ -0,0 +1,4 @@ +// should be x +type H_inline1 = (() => o) extends (() => infer o) ? o : never; + +type Result = H_inline1; // should be `string` \ No newline at end of file