Skip to content

Commit e24d886

Browse files
authored
Error on types named "undefined" (#57575)
1 parent 3fca8c8 commit e24d886

13 files changed

+360
-26
lines changed

src/compiler/checker.ts

+15-20
Original file line numberDiff line numberDiff line change
@@ -2255,9 +2255,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
22552255
var identityRelation = new Map<string, RelationComparisonResult>();
22562256
var enumRelation = new Map<string, RelationComparisonResult>();
22572257

2258-
var builtinGlobals = createSymbolTable();
2259-
builtinGlobals.set(undefinedSymbol.escapedName, undefinedSymbol);
2260-
22612258
// Extensions suggested for path imports when module resolution is node16 or higher.
22622259
// The first element of each tuple is the extension a file has.
22632260
// The second element of each tuple is the extension that should be used in a path import.
@@ -2720,20 +2717,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
27202717
}
27212718
}
27222719

2723-
function addToSymbolTable(target: SymbolTable, source: SymbolTable, message: DiagnosticMessage) {
2724-
source.forEach((sourceSymbol, id) => {
2725-
const targetSymbol = target.get(id);
2726-
if (targetSymbol) {
2727-
// Error on redeclarations
2728-
forEach(targetSymbol.declarations, addDeclarationDiagnostic(unescapeLeadingUnderscores(id), message));
2729-
}
2730-
else {
2731-
target.set(id, sourceSymbol);
2732-
}
2733-
});
2734-
2735-
function addDeclarationDiagnostic(id: string, message: DiagnosticMessage) {
2736-
return (declaration: Declaration) => diagnostics.add(createDiagnosticForNode(declaration, message, id));
2720+
function addUndefinedToGlobalsOrErrorOnRedeclaration() {
2721+
const name = undefinedSymbol.escapedName;
2722+
const targetSymbol = globals.get(name);
2723+
if (targetSymbol) {
2724+
forEach(targetSymbol.declarations, declaration => {
2725+
// checkTypeNameIsReserved will have added better diagnostics for type declarations.
2726+
if (!isTypeDeclaration(declaration)) {
2727+
diagnostics.add(createDiagnosticForNode(declaration, Diagnostics.Declaration_name_conflicts_with_built_in_global_identifier_0, unescapeLeadingUnderscores(name)));
2728+
}
2729+
});
2730+
}
2731+
else {
2732+
globals.set(name, undefinedSymbol);
27372733
}
27382734
}
27392735

@@ -44336,6 +44332,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4433644332
case "symbol":
4433744333
case "void":
4433844334
case "object":
44335+
case "undefined":
4433944336
error(name, message, name.escapedText as string);
4434044337
}
4434144338
}
@@ -48773,7 +48770,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4877348770
}
4877448771
if (!isExternalOrCommonJsModule(file)) {
4877548772
// It is an error for a non-external-module (i.e. script) to declare its own `globalThis`.
48776-
// We can't use `builtinGlobals` for this due to synthetic expando-namespace generation in JS files.
4877748773
const fileGlobalThisSymbol = file.locals!.get("globalThis" as __String);
4877848774
if (fileGlobalThisSymbol?.declarations) {
4877948775
for (const declaration of fileGlobalThisSymbol.declarations) {
@@ -48819,8 +48815,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4881948815
}
4882048816
}
4882148817

48822-
// Setup global builtins
48823-
addToSymbolTable(globals, builtinGlobals, Diagnostics.Declaration_name_conflicts_with_built_in_global_identifier_0);
48818+
addUndefinedToGlobalsOrErrorOnRedeclaration();
4882448819

4882548820
getSymbolLinks(undefinedSymbol).type = undefinedWideningType;
4882648821
getSymbolLinks(argumentsSymbol).type = getGlobalType("IArguments" as __String, /*arity*/ 0, /*reportErrors*/ true);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
typeNamedUndefined1.ts(3,17): error TS2457: Type alias name cannot be 'undefined'.
2+
typeNamedUndefined1.ts(13,13): error TS2457: Type alias name cannot be 'undefined'.
3+
4+
5+
==== typeNamedUndefined1.ts (2 errors) ====
6+
export namespace ns {
7+
const s = Symbol();
8+
export type undefined = typeof s;
9+
~~~~~~~~~
10+
!!! error TS2457: Type alias name cannot be 'undefined'.
11+
export function x(p: undefined): undefined { // global undefined
12+
return p;
13+
}
14+
}
15+
16+
export function x(p: ns.undefined) { // undefined from the namespace
17+
return p;
18+
}
19+
20+
export type undefined = "";
21+
~~~~~~~~~
22+
!!! error TS2457: Type alias name cannot be 'undefined'.
23+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//// [tests/cases/compiler/typeNamedUndefined1.ts] ////
2+
3+
//// [typeNamedUndefined1.ts]
4+
export namespace ns {
5+
const s = Symbol();
6+
export type undefined = typeof s;
7+
export function x(p: undefined): undefined { // global undefined
8+
return p;
9+
}
10+
}
11+
12+
export function x(p: ns.undefined) { // undefined from the namespace
13+
return p;
14+
}
15+
16+
export type undefined = "";
17+
18+
19+
//// [typeNamedUndefined1.js]
20+
export var ns;
21+
(function (ns) {
22+
const s = Symbol();
23+
function x(p) {
24+
return p;
25+
}
26+
ns.x = x;
27+
})(ns || (ns = {}));
28+
export function x(p) {
29+
return p;
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//// [tests/cases/compiler/typeNamedUndefined1.ts] ////
2+
3+
=== typeNamedUndefined1.ts ===
4+
export namespace ns {
5+
>ns : Symbol(ns, Decl(typeNamedUndefined1.ts, 0, 0))
6+
7+
const s = Symbol();
8+
>s : Symbol(s, Decl(typeNamedUndefined1.ts, 1, 9))
9+
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --))
10+
11+
export type undefined = typeof s;
12+
>undefined : Symbol(undefined, Decl(typeNamedUndefined1.ts, 1, 23))
13+
>s : Symbol(s, Decl(typeNamedUndefined1.ts, 1, 9))
14+
15+
export function x(p: undefined): undefined { // global undefined
16+
>x : Symbol(x, Decl(typeNamedUndefined1.ts, 2, 37))
17+
>p : Symbol(p, Decl(typeNamedUndefined1.ts, 3, 22))
18+
19+
return p;
20+
>p : Symbol(p, Decl(typeNamedUndefined1.ts, 3, 22))
21+
}
22+
}
23+
24+
export function x(p: ns.undefined) { // undefined from the namespace
25+
>x : Symbol(x, Decl(typeNamedUndefined1.ts, 6, 1))
26+
>p : Symbol(p, Decl(typeNamedUndefined1.ts, 8, 18))
27+
>ns : Symbol(ns, Decl(typeNamedUndefined1.ts, 0, 0))
28+
>undefined : Symbol(ns.undefined, Decl(typeNamedUndefined1.ts, 1, 23))
29+
30+
return p;
31+
>p : Symbol(p, Decl(typeNamedUndefined1.ts, 8, 18))
32+
}
33+
34+
export type undefined = "";
35+
>undefined : Symbol(undefined, Decl(typeNamedUndefined1.ts, 10, 1))
36+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//// [tests/cases/compiler/typeNamedUndefined1.ts] ////
2+
3+
=== typeNamedUndefined1.ts ===
4+
export namespace ns {
5+
>ns : typeof ns
6+
7+
const s = Symbol();
8+
>s : unique symbol
9+
>Symbol() : unique symbol
10+
>Symbol : SymbolConstructor
11+
12+
export type undefined = typeof s;
13+
>undefined : unique symbol
14+
>s : unique symbol
15+
16+
export function x(p: undefined): undefined { // global undefined
17+
>x : (p: undefined) => undefined
18+
>p : undefined
19+
20+
return p;
21+
>p : undefined
22+
}
23+
}
24+
25+
export function x(p: ns.undefined) { // undefined from the namespace
26+
>x : (p: ns.undefined) => symbol
27+
>p : unique symbol
28+
>ns : any
29+
30+
return p;
31+
>p : unique symbol
32+
}
33+
34+
export type undefined = "";
35+
>undefined : ""
36+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
typeNamedUndefined2.ts(4,21): error TS2457: Type alias name cannot be 'undefined'.
2+
typeNamedUndefined2.ts(17,17): error TS2457: Type alias name cannot be 'undefined'.
3+
4+
5+
==== typeNamedUndefined2.ts (2 errors) ====
6+
export namespace ns {
7+
export namespace undefined {
8+
export const s = Symbol();
9+
export type undefined = typeof s;
10+
~~~~~~~~~
11+
!!! error TS2457: Type alias name cannot be 'undefined'.
12+
};
13+
export function x(p: undefined): undefined {
14+
return p;
15+
}
16+
}
17+
18+
export function x(p: ns.undefined.undefined) {
19+
return p;
20+
}
21+
22+
export namespace undefined {
23+
export const s = Symbol();
24+
export type undefined = typeof s;
25+
~~~~~~~~~
26+
!!! error TS2457: Type alias name cannot be 'undefined'.
27+
};
28+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//// [tests/cases/compiler/typeNamedUndefined2.ts] ////
2+
3+
//// [typeNamedUndefined2.ts]
4+
export namespace ns {
5+
export namespace undefined {
6+
export const s = Symbol();
7+
export type undefined = typeof s;
8+
};
9+
export function x(p: undefined): undefined {
10+
return p;
11+
}
12+
}
13+
14+
export function x(p: ns.undefined.undefined) {
15+
return p;
16+
}
17+
18+
export namespace undefined {
19+
export const s = Symbol();
20+
export type undefined = typeof s;
21+
};
22+
23+
24+
//// [typeNamedUndefined2.js]
25+
export var ns;
26+
(function (ns) {
27+
let undefined;
28+
(function (undefined) {
29+
undefined.s = Symbol();
30+
})(undefined = ns.undefined || (ns.undefined = {}));
31+
;
32+
function x(p) {
33+
return p;
34+
}
35+
ns.x = x;
36+
})(ns || (ns = {}));
37+
export function x(p) {
38+
return p;
39+
}
40+
export var undefined;
41+
(function (undefined) {
42+
undefined.s = Symbol();
43+
})(undefined || (undefined = {}));
44+
;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//// [tests/cases/compiler/typeNamedUndefined2.ts] ////
2+
3+
=== typeNamedUndefined2.ts ===
4+
export namespace ns {
5+
>ns : Symbol(ns, Decl(typeNamedUndefined2.ts, 0, 0))
6+
7+
export namespace undefined {
8+
>undefined : Symbol(undefined, Decl(typeNamedUndefined2.ts, 0, 21))
9+
10+
export const s = Symbol();
11+
>s : Symbol(s, Decl(typeNamedUndefined2.ts, 2, 20))
12+
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --))
13+
14+
export type undefined = typeof s;
15+
>undefined : Symbol(undefined, Decl(typeNamedUndefined2.ts, 2, 34))
16+
>s : Symbol(s, Decl(typeNamedUndefined2.ts, 2, 20))
17+
18+
};
19+
export function x(p: undefined): undefined {
20+
>x : Symbol(x, Decl(typeNamedUndefined2.ts, 4, 6))
21+
>p : Symbol(p, Decl(typeNamedUndefined2.ts, 5, 22))
22+
23+
return p;
24+
>p : Symbol(p, Decl(typeNamedUndefined2.ts, 5, 22))
25+
}
26+
}
27+
28+
export function x(p: ns.undefined.undefined) {
29+
>x : Symbol(x, Decl(typeNamedUndefined2.ts, 8, 1))
30+
>p : Symbol(p, Decl(typeNamedUndefined2.ts, 10, 18))
31+
>ns : Symbol(ns, Decl(typeNamedUndefined2.ts, 0, 0))
32+
>undefined : Symbol(ns.undefined, Decl(typeNamedUndefined2.ts, 0, 21))
33+
>undefined : Symbol(ns.undefined.undefined, Decl(typeNamedUndefined2.ts, 2, 34))
34+
35+
return p;
36+
>p : Symbol(p, Decl(typeNamedUndefined2.ts, 10, 18))
37+
}
38+
39+
export namespace undefined {
40+
>undefined : Symbol(undefined, Decl(typeNamedUndefined2.ts, 12, 1))
41+
42+
export const s = Symbol();
43+
>s : Symbol(s, Decl(typeNamedUndefined2.ts, 15, 16))
44+
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --))
45+
46+
export type undefined = typeof s;
47+
>undefined : Symbol(undefined, Decl(typeNamedUndefined2.ts, 15, 30))
48+
>s : Symbol(s, Decl(typeNamedUndefined2.ts, 15, 16))
49+
50+
};
51+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//// [tests/cases/compiler/typeNamedUndefined2.ts] ////
2+
3+
=== typeNamedUndefined2.ts ===
4+
export namespace ns {
5+
>ns : typeof ns
6+
7+
export namespace undefined {
8+
>undefined : typeof undefined
9+
10+
export const s = Symbol();
11+
>s : unique symbol
12+
>Symbol() : unique symbol
13+
>Symbol : SymbolConstructor
14+
15+
export type undefined = typeof s;
16+
>undefined : unique symbol
17+
>s : unique symbol
18+
19+
};
20+
export function x(p: undefined): undefined {
21+
>x : (p: undefined) => undefined
22+
>p : undefined
23+
24+
return p;
25+
>p : undefined
26+
}
27+
}
28+
29+
export function x(p: ns.undefined.undefined) {
30+
>x : (p: ns.undefined.undefined) => symbol
31+
>p : unique symbol
32+
>ns : any
33+
>undefined : any
34+
35+
return p;
36+
>p : unique symbol
37+
}
38+
39+
export namespace undefined {
40+
>undefined : typeof undefined
41+
42+
export const s = Symbol();
43+
>s : unique symbol
44+
>Symbol() : unique symbol
45+
>Symbol : SymbolConstructor
46+
47+
export type undefined = typeof s;
48+
>undefined : unique symbol
49+
>s : unique symbol
50+
51+
};
52+

tests/baselines/reference/undefinedTypeAssignment1.errors.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
undefinedTypeAssignment1.ts(1,6): error TS2397: Declaration name conflicts with built-in global identifier 'undefined'.
1+
undefinedTypeAssignment1.ts(1,6): error TS2457: Type alias name cannot be 'undefined'.
22

33

44
==== undefinedTypeAssignment1.ts (1 errors) ====
55
type undefined = string;
66
~~~~~~~~~
7-
!!! error TS2397: Declaration name conflicts with built-in global identifier 'undefined'.
7+
!!! error TS2457: Type alias name cannot be 'undefined'.
88
function p(undefined = "wat") {
99
return undefined;
1010
}

0 commit comments

Comments
 (0)