Skip to content

Commit

Permalink
Do not expand type references in keyof and index access (#58715)
Browse files Browse the repository at this point in the history
  • Loading branch information
dragomirtitian authored May 31, 2024
1 parent fc42002 commit 389b579
Show file tree
Hide file tree
Showing 12 changed files with 375 additions and 45 deletions.
81 changes: 57 additions & 24 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8590,6 +8590,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return enterNewScope(context, node, getParametersInScope(node), getTypeParametersInScope(node));
}

function tryVisitTypeReference(node: TypeReferenceNode) {
if (canReuseTypeNode(context, node)) {
const { introducesError, node: newName } = trackExistingEntityName(node.typeName, context);
const typeArguments = visitNodes(node.typeArguments, visitExistingNodeTreeSymbols, isTypeNode);

if (!introducesError) {
const updated = factory.updateTypeReferenceNode(
node,
newName,
typeArguments,
);
return setTextRange(context, updated, node);
}
else {
const serializedName = serializeTypeName(context, node.typeName, /*isTypeOf*/ false, typeArguments);
if (serializedName) {
return setTextRange(context, serializedName, node.typeName);
}
}
}
}

function visitExistingNodeTreeSymbolsWorker(node: Node): Node | undefined {
if (isJSDocTypeExpression(node)) {
// Unwrap JSDocTypeExpressions
Expand Down Expand Up @@ -8682,7 +8704,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (canReuseTypeNode(context, node)) {
return node;
}
return serializeExistingTypeNode(context, node);
hadError = true;
return node;
}
if (isTypeParameterDeclaration(node)) {
return factory.updateTypeParameterDeclaration(
Expand All @@ -8693,27 +8716,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
visitNode(node.default, visitExistingNodeTreeSymbols, isTypeNode),
);
}

if (isIndexedAccessTypeNode(node) && isTypeReferenceNode(node.objectType)) {
const objectType = tryVisitTypeReference(node.objectType);
if (!objectType) {
hadError = true;
return node;
}
return factory.updateIndexedAccessTypeNode(node, objectType, visitNode(node.indexType, visitExistingNodeTreeSymbols, isTypeNode)!);
}

if (isTypeReferenceNode(node)) {
if (canReuseTypeNode(context, node)) {
const { introducesError, node: newName } = trackExistingEntityName(node.typeName, context);
const typeArguments = visitNodes(node.typeArguments, visitExistingNodeTreeSymbols, isTypeNode);

if (!introducesError) {
const updated = factory.updateTypeReferenceNode(
node,
newName,
typeArguments,
);
return setTextRange(context, updated, node);
}
else {
const serializedName = serializeTypeName(context, node.typeName, /*isTypeOf*/ false, typeArguments);
if (serializedName) {
return setTextRange(context, serializedName, node.typeName);
}
}
const result = tryVisitTypeReference(node);
if (result) {
return result;
}
return serializeExistingTypeNode(context, node);
hadError = true;
return node;
}
if (isLiteralImportTypeNode(node)) {
const nodeSymbol = getNodeLinks(node).resolvedSymbol;
Expand Down Expand Up @@ -8766,7 +8785,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (serializedName) {
return setTextRange(context, serializedName, node.exprName);
}
return serializeExistingTypeNode(context, node);
hadError = true;
return node;
}
return factory.updateTypeQueryNode(
node,
Expand Down Expand Up @@ -8838,9 +8858,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
);
}

if (isTypeOperatorNode(node) && node.operator === SyntaxKind.UniqueKeyword && node.type.kind === SyntaxKind.SymbolKeyword) {
if (!canReuseTypeNode(context, node)) {
return serializeExistingTypeNode(context, node);
if (isTypeOperatorNode(node)) {
if (node.operator === SyntaxKind.UniqueKeyword && node.type.kind === SyntaxKind.SymbolKeyword) {
if (!canReuseTypeNode(context, node)) {
hadError = true;
return node;
}
}
else if (node.operator === SyntaxKind.KeyOfKeyword) {
if (isTypeReferenceNode(node.type)) {
const type = tryVisitTypeReference(node.type);
if (!type) {
hadError = true;
return node;
}
return factory.updateTypeOperatorNode(node, type);
}
}
}

Expand Down
6 changes: 3 additions & 3 deletions tests/baselines/reference/correlatedUnions.types
Original file line number Diff line number Diff line change
Expand Up @@ -822,7 +822,7 @@ function ff1() {
}
function apply<K extends Keys>(funKey: K, ...args: ArgMap[K]) {
>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
> : ^ ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^ ^^^^^ ^^^^^^^^^ ^^^^^^^^^^ ^^^ ^^^^^^^^^
> : ^ ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^ ^^^^^ ^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^
>funKey : K
> : ^
>args : { sum: [a: number, b: number]; concat: [a: string, b: string, c: string]; }[K]
Expand Down Expand Up @@ -854,7 +854,7 @@ function ff1() {
>apply('sum', 1, 2) : void
> : ^^^^
>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
> : ^ ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^ ^^^^^ ^^^^^^^^^ ^^^^^^^^^^ ^^^ ^^^^^^^^^
> : ^ ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^ ^^^^^ ^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^
>'sum' : "sum"
> : ^^^^^
>1 : 1
Expand All @@ -868,7 +868,7 @@ function ff1() {
>apply('concat', 'str1', 'str2', 'str3' ) : void
> : ^^^^
>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
> : ^ ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^ ^^^^^ ^^^^^^^^^ ^^^^^^^^^^ ^^^ ^^^^^^^^^
> : ^ ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^ ^^^^^ ^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^
>'concat' : "concat"
> : ^^^^^^^^
>'str1' : "str1"
Expand Down
85 changes: 85 additions & 0 deletions tests/baselines/reference/declarationEmitAliasInlineing.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//// [tests/cases/compiler/declarationEmitAliasInlineing.ts] ////

//// [a.ts]
type O = {
prop: string
prop2: string
}

type I = {
prop: string
}

export const fn = (v: O['prop'], p: Omit<O, 'prop'>, key: keyof O, p2: Omit<O, keyof I>) => {};

//// [aExp.ts]
export type O = {
prop: string
prop2: string
}

export type I = {
prop: string
}

export const fnExp = (v: O['prop'], p: Omit<O, 'prop'>, key: keyof O, p2: Omit<O, keyof I>) => {};

//// [b.ts]
import {fn} from './a'
import {fnExp} from './aExp'
export const f = fn;
export const fExp = fnExp;

//// [a.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.fn = void 0;
var fn = function (v, p, key, p2) { };
exports.fn = fn;
//// [aExp.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.fnExp = void 0;
var fnExp = function (v, p, key, p2) { };
exports.fnExp = fnExp;
//// [b.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.fExp = exports.f = void 0;
var a_1 = require("./a");
var aExp_1 = require("./aExp");
exports.f = a_1.fn;
exports.fExp = aExp_1.fnExp;


//// [a.d.ts]
type O = {
prop: string;
prop2: string;
};
type I = {
prop: string;
};
export declare const fn: (v: O["prop"], p: Omit<O, "prop">, key: keyof O, p2: Omit<O, keyof I>) => void;
export {};
//// [aExp.d.ts]
export type O = {
prop: string;
prop2: string;
};
export type I = {
prop: string;
};
export declare const fnExp: (v: O["prop"], p: Omit<O, "prop">, key: keyof O, p2: Omit<O, keyof I>) => void;
//// [b.d.ts]
export declare const f: (v: string, p: Omit<{
prop: string;
prop2: string;
}, "prop">, key: keyof {
prop: string;
prop2: string;
}, p2: Omit<{
prop: string;
prop2: string;
}, "prop">) => void;
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;
81 changes: 81 additions & 0 deletions tests/baselines/reference/declarationEmitAliasInlineing.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
//// [tests/cases/compiler/declarationEmitAliasInlineing.ts] ////

=== a.ts ===
type O = {
>O : Symbol(O, Decl(a.ts, 0, 0))

prop: string
>prop : Symbol(prop, Decl(a.ts, 0, 10))

prop2: string
>prop2 : Symbol(prop2, Decl(a.ts, 1, 16))
}

type I = {
>I : Symbol(I, Decl(a.ts, 3, 1))

prop: string
>prop : Symbol(prop, Decl(a.ts, 5, 10))
}

export const fn = (v: O['prop'], p: Omit<O, 'prop'>, key: keyof O, p2: Omit<O, keyof I>) => {};
>fn : Symbol(fn, Decl(a.ts, 9, 12))
>v : Symbol(v, Decl(a.ts, 9, 19))
>O : Symbol(O, Decl(a.ts, 0, 0))
>p : Symbol(p, Decl(a.ts, 9, 32))
>Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --))
>O : Symbol(O, Decl(a.ts, 0, 0))
>key : Symbol(key, Decl(a.ts, 9, 52))
>O : Symbol(O, Decl(a.ts, 0, 0))
>p2 : Symbol(p2, Decl(a.ts, 9, 66))
>Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --))
>O : Symbol(O, Decl(a.ts, 0, 0))
>I : Symbol(I, Decl(a.ts, 3, 1))

=== aExp.ts ===
export type O = {
>O : Symbol(O, Decl(aExp.ts, 0, 0))

prop: string
>prop : Symbol(prop, Decl(aExp.ts, 0, 17))

prop2: string
>prop2 : Symbol(prop2, Decl(aExp.ts, 1, 16))
}

export type I = {
>I : Symbol(I, Decl(aExp.ts, 3, 1))

prop: string
>prop : Symbol(prop, Decl(aExp.ts, 5, 17))
}

export const fnExp = (v: O['prop'], p: Omit<O, 'prop'>, key: keyof O, p2: Omit<O, keyof I>) => {};
>fnExp : Symbol(fnExp, Decl(aExp.ts, 9, 12))
>v : Symbol(v, Decl(aExp.ts, 9, 22))
>O : Symbol(O, Decl(aExp.ts, 0, 0))
>p : Symbol(p, Decl(aExp.ts, 9, 35))
>Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --))
>O : Symbol(O, Decl(aExp.ts, 0, 0))
>key : Symbol(key, Decl(aExp.ts, 9, 55))
>O : Symbol(O, Decl(aExp.ts, 0, 0))
>p2 : Symbol(p2, Decl(aExp.ts, 9, 69))
>Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --))
>O : Symbol(O, Decl(aExp.ts, 0, 0))
>I : Symbol(I, Decl(aExp.ts, 3, 1))

=== b.ts ===
import {fn} from './a'
>fn : Symbol(fn, Decl(b.ts, 0, 8))

import {fnExp} from './aExp'
>fnExp : Symbol(fnExp, Decl(b.ts, 1, 8))

export const f = fn;
>f : Symbol(f, Decl(b.ts, 2, 12))
>fn : Symbol(fn, Decl(b.ts, 0, 8))

export const fExp = fnExp;
>fExp : Symbol(fExp, Decl(b.ts, 3, 12))
>fnExp : Symbol(fnExp, Decl(b.ts, 1, 8))

Loading

0 comments on commit 389b579

Please sign in to comment.