Skip to content

Commit 389b579

Browse files
Do not expand type references in keyof and index access (#58715)
1 parent fc42002 commit 389b579

12 files changed

+375
-45
lines changed

src/compiler/checker.ts

Lines changed: 57 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8590,6 +8590,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
85908590
return enterNewScope(context, node, getParametersInScope(node), getTypeParametersInScope(node));
85918591
}
85928592

8593+
function tryVisitTypeReference(node: TypeReferenceNode) {
8594+
if (canReuseTypeNode(context, node)) {
8595+
const { introducesError, node: newName } = trackExistingEntityName(node.typeName, context);
8596+
const typeArguments = visitNodes(node.typeArguments, visitExistingNodeTreeSymbols, isTypeNode);
8597+
8598+
if (!introducesError) {
8599+
const updated = factory.updateTypeReferenceNode(
8600+
node,
8601+
newName,
8602+
typeArguments,
8603+
);
8604+
return setTextRange(context, updated, node);
8605+
}
8606+
else {
8607+
const serializedName = serializeTypeName(context, node.typeName, /*isTypeOf*/ false, typeArguments);
8608+
if (serializedName) {
8609+
return setTextRange(context, serializedName, node.typeName);
8610+
}
8611+
}
8612+
}
8613+
}
8614+
85938615
function visitExistingNodeTreeSymbolsWorker(node: Node): Node | undefined {
85948616
if (isJSDocTypeExpression(node)) {
85958617
// Unwrap JSDocTypeExpressions
@@ -8682,7 +8704,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
86828704
if (canReuseTypeNode(context, node)) {
86838705
return node;
86848706
}
8685-
return serializeExistingTypeNode(context, node);
8707+
hadError = true;
8708+
return node;
86868709
}
86878710
if (isTypeParameterDeclaration(node)) {
86888711
return factory.updateTypeParameterDeclaration(
@@ -8693,27 +8716,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
86938716
visitNode(node.default, visitExistingNodeTreeSymbols, isTypeNode),
86948717
);
86958718
}
8719+
8720+
if (isIndexedAccessTypeNode(node) && isTypeReferenceNode(node.objectType)) {
8721+
const objectType = tryVisitTypeReference(node.objectType);
8722+
if (!objectType) {
8723+
hadError = true;
8724+
return node;
8725+
}
8726+
return factory.updateIndexedAccessTypeNode(node, objectType, visitNode(node.indexType, visitExistingNodeTreeSymbols, isTypeNode)!);
8727+
}
8728+
86968729
if (isTypeReferenceNode(node)) {
8697-
if (canReuseTypeNode(context, node)) {
8698-
const { introducesError, node: newName } = trackExistingEntityName(node.typeName, context);
8699-
const typeArguments = visitNodes(node.typeArguments, visitExistingNodeTreeSymbols, isTypeNode);
8700-
8701-
if (!introducesError) {
8702-
const updated = factory.updateTypeReferenceNode(
8703-
node,
8704-
newName,
8705-
typeArguments,
8706-
);
8707-
return setTextRange(context, updated, node);
8708-
}
8709-
else {
8710-
const serializedName = serializeTypeName(context, node.typeName, /*isTypeOf*/ false, typeArguments);
8711-
if (serializedName) {
8712-
return setTextRange(context, serializedName, node.typeName);
8713-
}
8714-
}
8730+
const result = tryVisitTypeReference(node);
8731+
if (result) {
8732+
return result;
87158733
}
8716-
return serializeExistingTypeNode(context, node);
8734+
hadError = true;
8735+
return node;
87178736
}
87188737
if (isLiteralImportTypeNode(node)) {
87198738
const nodeSymbol = getNodeLinks(node).resolvedSymbol;
@@ -8766,7 +8785,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
87668785
if (serializedName) {
87678786
return setTextRange(context, serializedName, node.exprName);
87688787
}
8769-
return serializeExistingTypeNode(context, node);
8788+
hadError = true;
8789+
return node;
87708790
}
87718791
return factory.updateTypeQueryNode(
87728792
node,
@@ -8838,9 +8858,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
88388858
);
88398859
}
88408860

8841-
if (isTypeOperatorNode(node) && node.operator === SyntaxKind.UniqueKeyword && node.type.kind === SyntaxKind.SymbolKeyword) {
8842-
if (!canReuseTypeNode(context, node)) {
8843-
return serializeExistingTypeNode(context, node);
8861+
if (isTypeOperatorNode(node)) {
8862+
if (node.operator === SyntaxKind.UniqueKeyword && node.type.kind === SyntaxKind.SymbolKeyword) {
8863+
if (!canReuseTypeNode(context, node)) {
8864+
hadError = true;
8865+
return node;
8866+
}
8867+
}
8868+
else if (node.operator === SyntaxKind.KeyOfKeyword) {
8869+
if (isTypeReferenceNode(node.type)) {
8870+
const type = tryVisitTypeReference(node.type);
8871+
if (!type) {
8872+
hadError = true;
8873+
return node;
8874+
}
8875+
return factory.updateTypeOperatorNode(node, type);
8876+
}
88448877
}
88458878
}
88468879

tests/baselines/reference/correlatedUnions.types

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -822,7 +822,7 @@ function ff1() {
822822
}
823823
function apply<K extends Keys>(funKey: K, ...args: ArgMap[K]) {
824824
>apply : <K extends keyof { sum: [a: number, b: number]; concat: [a: string, b: string, c: string]; }>(funKey: K, ...args: { sum: [a: number, b: number]; concat: [a: string, b: string, c: string]; }[K]) => void
825-
> : ^ ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^ ^^^^^ ^^^^^^^^^ ^^^^^^^^^^ ^^^ ^^^^^^^^^
825+
> : ^ ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^ ^^^^^ ^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^
826826
>funKey : K
827827
> : ^
828828
>args : { sum: [a: number, b: number]; concat: [a: string, b: string, c: string]; }[K]
@@ -854,7 +854,7 @@ function ff1() {
854854
>apply('sum', 1, 2) : void
855855
> : ^^^^
856856
>apply : <K extends keyof { sum: [a: number, b: number]; concat: [a: string, b: string, c: string]; }>(funKey: K, ...args: { sum: [a: number, b: number]; concat: [a: string, b: string, c: string]; }[K]) => void
857-
> : ^ ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^ ^^^^^ ^^^^^^^^^ ^^^^^^^^^^ ^^^ ^^^^^^^^^
857+
> : ^ ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^ ^^^^^ ^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^
858858
>'sum' : "sum"
859859
> : ^^^^^
860860
>1 : 1
@@ -868,7 +868,7 @@ function ff1() {
868868
>apply('concat', 'str1', 'str2', 'str3' ) : void
869869
> : ^^^^
870870
>apply : <K extends keyof { sum: [a: number, b: number]; concat: [a: string, b: string, c: string]; }>(funKey: K, ...args: { sum: [a: number, b: number]; concat: [a: string, b: string, c: string]; }[K]) => void
871-
> : ^ ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^ ^^^^^ ^^^^^^^^^ ^^^^^^^^^^ ^^^ ^^^^^^^^^
871+
> : ^ ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^ ^^^^^ ^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^
872872
>'concat' : "concat"
873873
> : ^^^^^^^^
874874
>'str1' : "str1"
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
//// [tests/cases/compiler/declarationEmitAliasInlineing.ts] ////
2+
3+
//// [a.ts]
4+
type O = {
5+
prop: string
6+
prop2: string
7+
}
8+
9+
type I = {
10+
prop: string
11+
}
12+
13+
export const fn = (v: O['prop'], p: Omit<O, 'prop'>, key: keyof O, p2: Omit<O, keyof I>) => {};
14+
15+
//// [aExp.ts]
16+
export type O = {
17+
prop: string
18+
prop2: string
19+
}
20+
21+
export type I = {
22+
prop: string
23+
}
24+
25+
export const fnExp = (v: O['prop'], p: Omit<O, 'prop'>, key: keyof O, p2: Omit<O, keyof I>) => {};
26+
27+
//// [b.ts]
28+
import {fn} from './a'
29+
import {fnExp} from './aExp'
30+
export const f = fn;
31+
export const fExp = fnExp;
32+
33+
//// [a.js]
34+
"use strict";
35+
Object.defineProperty(exports, "__esModule", { value: true });
36+
exports.fn = void 0;
37+
var fn = function (v, p, key, p2) { };
38+
exports.fn = fn;
39+
//// [aExp.js]
40+
"use strict";
41+
Object.defineProperty(exports, "__esModule", { value: true });
42+
exports.fnExp = void 0;
43+
var fnExp = function (v, p, key, p2) { };
44+
exports.fnExp = fnExp;
45+
//// [b.js]
46+
"use strict";
47+
Object.defineProperty(exports, "__esModule", { value: true });
48+
exports.fExp = exports.f = void 0;
49+
var a_1 = require("./a");
50+
var aExp_1 = require("./aExp");
51+
exports.f = a_1.fn;
52+
exports.fExp = aExp_1.fnExp;
53+
54+
55+
//// [a.d.ts]
56+
type O = {
57+
prop: string;
58+
prop2: string;
59+
};
60+
type I = {
61+
prop: string;
62+
};
63+
export declare const fn: (v: O["prop"], p: Omit<O, "prop">, key: keyof O, p2: Omit<O, keyof I>) => void;
64+
export {};
65+
//// [aExp.d.ts]
66+
export type O = {
67+
prop: string;
68+
prop2: string;
69+
};
70+
export type I = {
71+
prop: string;
72+
};
73+
export declare const fnExp: (v: O["prop"], p: Omit<O, "prop">, key: keyof O, p2: Omit<O, keyof I>) => void;
74+
//// [b.d.ts]
75+
export declare const f: (v: string, p: Omit<{
76+
prop: string;
77+
prop2: string;
78+
}, "prop">, key: keyof {
79+
prop: string;
80+
prop2: string;
81+
}, p2: Omit<{
82+
prop: string;
83+
prop2: string;
84+
}, "prop">) => void;
85+
export declare const fExp: (v: import("./aExp").O["prop"], p: Omit<import("./aExp").O, "prop">, key: keyof import("./aExp").O, p2: Omit<import("./aExp").O, keyof import("./aExp").I>) => void;
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
//// [tests/cases/compiler/declarationEmitAliasInlineing.ts] ////
2+
3+
=== a.ts ===
4+
type O = {
5+
>O : Symbol(O, Decl(a.ts, 0, 0))
6+
7+
prop: string
8+
>prop : Symbol(prop, Decl(a.ts, 0, 10))
9+
10+
prop2: string
11+
>prop2 : Symbol(prop2, Decl(a.ts, 1, 16))
12+
}
13+
14+
type I = {
15+
>I : Symbol(I, Decl(a.ts, 3, 1))
16+
17+
prop: string
18+
>prop : Symbol(prop, Decl(a.ts, 5, 10))
19+
}
20+
21+
export const fn = (v: O['prop'], p: Omit<O, 'prop'>, key: keyof O, p2: Omit<O, keyof I>) => {};
22+
>fn : Symbol(fn, Decl(a.ts, 9, 12))
23+
>v : Symbol(v, Decl(a.ts, 9, 19))
24+
>O : Symbol(O, Decl(a.ts, 0, 0))
25+
>p : Symbol(p, Decl(a.ts, 9, 32))
26+
>Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --))
27+
>O : Symbol(O, Decl(a.ts, 0, 0))
28+
>key : Symbol(key, Decl(a.ts, 9, 52))
29+
>O : Symbol(O, Decl(a.ts, 0, 0))
30+
>p2 : Symbol(p2, Decl(a.ts, 9, 66))
31+
>Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --))
32+
>O : Symbol(O, Decl(a.ts, 0, 0))
33+
>I : Symbol(I, Decl(a.ts, 3, 1))
34+
35+
=== aExp.ts ===
36+
export type O = {
37+
>O : Symbol(O, Decl(aExp.ts, 0, 0))
38+
39+
prop: string
40+
>prop : Symbol(prop, Decl(aExp.ts, 0, 17))
41+
42+
prop2: string
43+
>prop2 : Symbol(prop2, Decl(aExp.ts, 1, 16))
44+
}
45+
46+
export type I = {
47+
>I : Symbol(I, Decl(aExp.ts, 3, 1))
48+
49+
prop: string
50+
>prop : Symbol(prop, Decl(aExp.ts, 5, 17))
51+
}
52+
53+
export const fnExp = (v: O['prop'], p: Omit<O, 'prop'>, key: keyof O, p2: Omit<O, keyof I>) => {};
54+
>fnExp : Symbol(fnExp, Decl(aExp.ts, 9, 12))
55+
>v : Symbol(v, Decl(aExp.ts, 9, 22))
56+
>O : Symbol(O, Decl(aExp.ts, 0, 0))
57+
>p : Symbol(p, Decl(aExp.ts, 9, 35))
58+
>Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --))
59+
>O : Symbol(O, Decl(aExp.ts, 0, 0))
60+
>key : Symbol(key, Decl(aExp.ts, 9, 55))
61+
>O : Symbol(O, Decl(aExp.ts, 0, 0))
62+
>p2 : Symbol(p2, Decl(aExp.ts, 9, 69))
63+
>Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --))
64+
>O : Symbol(O, Decl(aExp.ts, 0, 0))
65+
>I : Symbol(I, Decl(aExp.ts, 3, 1))
66+
67+
=== b.ts ===
68+
import {fn} from './a'
69+
>fn : Symbol(fn, Decl(b.ts, 0, 8))
70+
71+
import {fnExp} from './aExp'
72+
>fnExp : Symbol(fnExp, Decl(b.ts, 1, 8))
73+
74+
export const f = fn;
75+
>f : Symbol(f, Decl(b.ts, 2, 12))
76+
>fn : Symbol(fn, Decl(b.ts, 0, 8))
77+
78+
export const fExp = fnExp;
79+
>fExp : Symbol(fExp, Decl(b.ts, 3, 12))
80+
>fnExp : Symbol(fnExp, Decl(b.ts, 1, 8))
81+

0 commit comments

Comments
 (0)