Skip to content

Commit

Permalink
Merge pull request #31337 from microsoft/fixConditionalTypeParameterR…
Browse files Browse the repository at this point in the history
…eference

Fix type parameter leakage in conditional types
  • Loading branch information
ahejlsberg committed May 10, 2019
2 parents d8f2702 + 1366cc7 commit bca2808
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 18 deletions.
24 changes: 6 additions & 18 deletions src/compiler/checker.ts
Expand Up @@ -10482,29 +10482,14 @@ namespace ts {
return result;
}

function isPossiblyReferencedInConditionalType(tp: TypeParameter, node: Node) {
if (isTypeParameterPossiblyReferenced(tp, node)) {
return true;
}
while (node) {
if (node.kind === SyntaxKind.ConditionalType) {
if (isTypeParameterPossiblyReferenced(tp, (<ConditionalTypeNode>node).extendsType)) {
return true;
}
}
node = node.parent;
}
return false;
}

function getTypeFromConditionalTypeNode(node: ConditionalTypeNode): Type {
const links = getNodeLinks(node);
if (!links.resolvedType) {
const checkType = getTypeFromTypeNode(node.checkType);
const aliasSymbol = getAliasSymbolForTypeNode(node);
const aliasTypeArguments = getTypeArgumentsForAliasSymbol(aliasSymbol);
const allOuterTypeParameters = getOuterTypeParameters(node, /*includeThisTypes*/ true);
const outerTypeParameters = aliasTypeArguments ? allOuterTypeParameters : filter(allOuterTypeParameters, tp => isPossiblyReferencedInConditionalType(tp, node));
const outerTypeParameters = aliasTypeArguments ? allOuterTypeParameters : filter(allOuterTypeParameters, tp => isTypeParameterPossiblyReferenced(tp, node));
const root: ConditionalRoot = {
node,
checkType,
Expand Down Expand Up @@ -11198,9 +11183,12 @@ namespace ts {
// type parameter, or if the node contains type queries, we consider the type parameter possibly referenced.
if (tp.symbol && tp.symbol.declarations && tp.symbol.declarations.length === 1) {
const container = tp.symbol.declarations[0].parent;
if (findAncestor(node, n => n.kind === SyntaxKind.Block ? "quit" : n === container)) {
return !!forEachChild(node, containsReference);
for (let n = node; n !== container; n = n.parent) {
if (!n || n.kind === SyntaxKind.Block || n.kind === SyntaxKind.ConditionalType && forEachChild((<ConditionalTypeNode>n).extendsType, containsReference)) {
return true;
}
}
return !!forEachChild(node, containsReference);
}
return true;
function containsReference(node: Node): boolean {
Expand Down
6 changes: 6 additions & 0 deletions tests/baselines/reference/conditionalTypes2.errors.txt
Expand Up @@ -267,4 +267,10 @@ tests/cases/conformance/types/conditional/conditionalTypes2.ts(75,12): error TS2
};
type PCCA = ProductComplementComplement['a'];
type PCCB = ProductComplementComplement['b'];

// Repro from #31326

type Hmm<T, U extends T> = U extends T ? { [K in keyof U]: number } : never;
type What = Hmm<{}, { a: string }>
const w: What = { a: 4 };

14 changes: 14 additions & 0 deletions tests/baselines/reference/conditionalTypes2.js
Expand Up @@ -188,6 +188,12 @@ type ProductComplementComplement = {
};
type PCCA = ProductComplementComplement['a'];
type PCCB = ProductComplementComplement['b'];

// Repro from #31326

type Hmm<T, U extends T> = U extends T ? { [K in keyof U]: number } : never;
type What = Hmm<{}, { a: string }>
const w: What = { a: 4 };


//// [conditionalTypes2.js]
Expand Down Expand Up @@ -265,6 +271,7 @@ function foo(value) {
toString2(value);
}
}
var w = { a: 4 };


//// [conditionalTypes2.d.ts]
Expand Down Expand Up @@ -392,3 +399,10 @@ declare type ProductComplementComplement = {
};
declare type PCCA = ProductComplementComplement['a'];
declare type PCCB = ProductComplementComplement['b'];
declare type Hmm<T, U extends T> = U extends T ? {
[K in keyof U]: number;
} : never;
declare type What = Hmm<{}, {
a: string;
}>;
declare const w: What;
22 changes: 22 additions & 0 deletions tests/baselines/reference/conditionalTypes2.symbols
Expand Up @@ -685,3 +685,25 @@ type PCCB = ProductComplementComplement['b'];
>PCCB : Symbol(PCCB, Decl(conditionalTypes2.ts, 187, 45))
>ProductComplementComplement : Symbol(ProductComplementComplement, Decl(conditionalTypes2.ts, 181, 34))

// Repro from #31326

type Hmm<T, U extends T> = U extends T ? { [K in keyof U]: number } : never;
>Hmm : Symbol(Hmm, Decl(conditionalTypes2.ts, 188, 45))
>T : Symbol(T, Decl(conditionalTypes2.ts, 192, 9))
>U : Symbol(U, Decl(conditionalTypes2.ts, 192, 11))
>T : Symbol(T, Decl(conditionalTypes2.ts, 192, 9))
>U : Symbol(U, Decl(conditionalTypes2.ts, 192, 11))
>T : Symbol(T, Decl(conditionalTypes2.ts, 192, 9))
>K : Symbol(K, Decl(conditionalTypes2.ts, 192, 44))
>U : Symbol(U, Decl(conditionalTypes2.ts, 192, 11))

type What = Hmm<{}, { a: string }>
>What : Symbol(What, Decl(conditionalTypes2.ts, 192, 76))
>Hmm : Symbol(Hmm, Decl(conditionalTypes2.ts, 188, 45))
>a : Symbol(a, Decl(conditionalTypes2.ts, 193, 21))

const w: What = { a: 4 };
>w : Symbol(w, Decl(conditionalTypes2.ts, 194, 5))
>What : Symbol(What, Decl(conditionalTypes2.ts, 192, 76))
>a : Symbol(a, Decl(conditionalTypes2.ts, 194, 17))

15 changes: 15 additions & 0 deletions tests/baselines/reference/conditionalTypes2.types
Expand Up @@ -431,3 +431,18 @@ type PCCA = ProductComplementComplement['a'];
type PCCB = ProductComplementComplement['b'];
>PCCB : Product<"b", 1>

// Repro from #31326

type Hmm<T, U extends T> = U extends T ? { [K in keyof U]: number } : never;
>Hmm : Hmm<T, U>

type What = Hmm<{}, { a: string }>
>What : { a: number; }
>a : string

const w: What = { a: 4 };
>w : { a: number; }
>{ a: 4 } : { a: number; }
>a : number
>4 : 4

Expand Up @@ -190,3 +190,9 @@ type ProductComplementComplement = {
};
type PCCA = ProductComplementComplement['a'];
type PCCB = ProductComplementComplement['b'];

// Repro from #31326

type Hmm<T, U extends T> = U extends T ? { [K in keyof U]: number } : never;
type What = Hmm<{}, { a: string }>
const w: What = { a: 4 };

0 comments on commit bca2808

Please sign in to comment.