Skip to content

Commit 32054f1

Browse files
authored
Forbid accessing block-scoped variables on globalThis (#30510)
* Forbid accessing const & let on globalThis It's just an error; you still get the type of the property. * Disallow access of blockscoped vars on globalThis Also change Array, Function, String, et al from `const` to `var` so that they remain accessible via `globalThis.String`. * Update baselines after lib.d.ts change Note especially the change in redefineArray, which is now allowed as long as you provide a type that is assignable to ArrayConstructor. * Remove blockscoped vars from typeof globalThis Unlike forbidding them, this removes the properties entirely. Unfortunately, this means that accessing these properties is only an error with noImplicitAny, and that error is quite confusing. Let's discuss our options. I see 3: 1. Forbid access of block-scoped vars as properties (in all flag settings), but leave them on the type. Simple to implement. 2. Remove block-scoped vars from the globalThis type. Has the bad error/flag behaviour described above, but simple to implement. 3. Remove block-scoped vars from the globalThis type. Also, forbid accessing them by executing another resolveName lookup for failed property accesses on globalThisSymbol. If the second lookup returns a blockscoped var, issue an error instead of falling back to the index signature. This seems too complex to me. * Update baselines * Better error for block-scoped usage on globalThis So that value-space references have as clear an error as type-space references. * Update fourslash tests * Fix semi-colon lint * Don't copy so much when filtering blockscoped vars
1 parent e20b87f commit 32054f1

32 files changed

+591
-168
lines changed

Diff for: src/compiler/checker.ts

+18-2
Original file line numberDiff line numberDiff line change
@@ -7116,6 +7116,15 @@ namespace ts {
71167116
let stringIndexInfo: IndexInfo | undefined;
71177117
if (symbol.exports) {
71187118
members = getExportsOfSymbol(symbol);
7119+
if (symbol === globalThisSymbol) {
7120+
const varsOnly = createMap<Symbol>() as SymbolTable;
7121+
members.forEach(p => {
7122+
if (!(p.flags & SymbolFlags.BlockScoped)) {
7123+
varsOnly.set(p.escapedName, p);
7124+
}
7125+
});
7126+
members = varsOnly;
7127+
}
71197128
}
71207129
setStructuredTypeMembers(type, members, emptyArray, emptyArray, undefined, undefined);
71217130
if (symbol.flags & SymbolFlags.Class) {
@@ -9877,6 +9886,7 @@ namespace ts {
98779886
getNodeLinks(accessNode!).resolvedSymbol = prop;
98789887
}
98799888
}
9889+
98809890
const propType = getTypeOfSymbol(prop);
98819891
return accessExpression && getAssignmentTargetKind(accessExpression) !== AssignmentKind.Definite ?
98829892
getFlowTypeOfReference(accessExpression, propType) :
@@ -9920,7 +9930,10 @@ namespace ts {
99209930
return anyType;
99219931
}
99229932
if (accessExpression && !isConstEnumObjectType(objectType)) {
9923-
if (noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors) {
9933+
if (objectType.symbol === globalThisSymbol && propName !== undefined && globalThisSymbol.exports!.has(propName) && (globalThisSymbol.exports!.get(propName)!.flags & SymbolFlags.BlockScoped)) {
9934+
error(accessExpression, Diagnostics.Property_0_does_not_exist_on_type_1, unescapeLeadingUnderscores(propName), typeToString(objectType));
9935+
}
9936+
else if (noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors) {
99249937
if (propName !== undefined && typeHasStaticProperty(propName, objectType)) {
99259938
error(accessExpression, Diagnostics.Property_0_is_a_static_member_of_type_1, propName as string, typeToString(objectType));
99269939
}
@@ -19515,7 +19528,10 @@ namespace ts {
1951519528
return anyType;
1951619529
}
1951719530
if (leftType.symbol === globalThisSymbol) {
19518-
if (noImplicitAny) {
19531+
if (globalThisSymbol.exports!.has(right.escapedText) && (globalThisSymbol.exports!.get(right.escapedText)!.flags & SymbolFlags.BlockScoped)) {
19532+
error(right, Diagnostics.Property_0_does_not_exist_on_type_1, unescapeLeadingUnderscores(right.escapedText), typeToString(leftType));
19533+
}
19534+
else if (noImplicitAny) {
1951919535
error(right, Diagnostics.Element_implicitly_has_an_any_type_because_type_0_has_no_index_signature, typeToString(leftType));
1952019536
}
1952119537
return anyType;

Diff for: src/harness/fourslash.ts

+59-59
Original file line numberDiff line numberDiff line change
@@ -4425,7 +4425,7 @@ namespace FourSlashInterface {
44254425
}
44264426
export namespace Completion {
44274427
const functionEntry = (name: string): ExpectedCompletionEntryObject => ({ name, kind: "function", kindModifiers: "declare" });
4428-
const constEntry = (name: string): ExpectedCompletionEntryObject => ({ name, kind: "const", kindModifiers: "declare" });
4428+
const varEntry = (name: string): ExpectedCompletionEntryObject => ({ name, kind: "var", kindModifiers: "declare" });
44294429
const moduleEntry = (name: string): ExpectedCompletionEntryObject => ({ name, kind: "module", kindModifiers: "declare" });
44304430
const keywordEntry = (name: string): ExpectedCompletionEntryObject => ({ name, kind: "keyword" });
44314431
const methodEntry = (name: string): ExpectedCompletionEntryObject => ({ name, kind: "method", kindModifiers: "declare" });
@@ -4448,48 +4448,48 @@ namespace FourSlashInterface {
44484448
typeEntry("PropertyKey"),
44494449
interfaceEntry("PropertyDescriptor"),
44504450
interfaceEntry("PropertyDescriptorMap"),
4451-
constEntry("Object"),
4451+
varEntry("Object"),
44524452
interfaceEntry("ObjectConstructor"),
4453-
constEntry("Function"),
4453+
varEntry("Function"),
44544454
interfaceEntry("FunctionConstructor"),
44554455
typeEntry("ThisParameterType"),
44564456
typeEntry("OmitThisParameter"),
44574457
interfaceEntry("CallableFunction"),
44584458
interfaceEntry("NewableFunction"),
44594459
interfaceEntry("IArguments"),
4460-
constEntry("String"),
4460+
varEntry("String"),
44614461
interfaceEntry("StringConstructor"),
4462-
constEntry("Boolean"),
4462+
varEntry("Boolean"),
44634463
interfaceEntry("BooleanConstructor"),
4464-
constEntry("Number"),
4464+
varEntry("Number"),
44654465
interfaceEntry("NumberConstructor"),
44664466
interfaceEntry("TemplateStringsArray"),
44674467
interfaceEntry("ImportMeta"),
4468-
constEntry("Math"),
4469-
constEntry("Date"),
4468+
varEntry("Math"),
4469+
varEntry("Date"),
44704470
interfaceEntry("DateConstructor"),
44714471
interfaceEntry("RegExpMatchArray"),
44724472
interfaceEntry("RegExpExecArray"),
4473-
constEntry("RegExp"),
4473+
varEntry("RegExp"),
44744474
interfaceEntry("RegExpConstructor"),
4475-
constEntry("Error"),
4475+
varEntry("Error"),
44764476
interfaceEntry("ErrorConstructor"),
4477-
constEntry("EvalError"),
4477+
varEntry("EvalError"),
44784478
interfaceEntry("EvalErrorConstructor"),
4479-
constEntry("RangeError"),
4479+
varEntry("RangeError"),
44804480
interfaceEntry("RangeErrorConstructor"),
4481-
constEntry("ReferenceError"),
4481+
varEntry("ReferenceError"),
44824482
interfaceEntry("ReferenceErrorConstructor"),
4483-
constEntry("SyntaxError"),
4483+
varEntry("SyntaxError"),
44844484
interfaceEntry("SyntaxErrorConstructor"),
4485-
constEntry("TypeError"),
4485+
varEntry("TypeError"),
44864486
interfaceEntry("TypeErrorConstructor"),
4487-
constEntry("URIError"),
4487+
varEntry("URIError"),
44884488
interfaceEntry("URIErrorConstructor"),
4489-
constEntry("JSON"),
4489+
varEntry("JSON"),
44904490
interfaceEntry("ReadonlyArray"),
44914491
interfaceEntry("ConcatArray"),
4492-
constEntry("Array"),
4492+
varEntry("Array"),
44934493
interfaceEntry("ArrayConstructor"),
44944494
interfaceEntry("TypedPropertyDescriptor"),
44954495
typeEntry("ClassDecorator"),
@@ -4513,30 +4513,30 @@ namespace FourSlashInterface {
45134513
typeEntry("ReturnType"),
45144514
typeEntry("InstanceType"),
45154515
interfaceEntry("ThisType"),
4516-
constEntry("ArrayBuffer"),
4516+
varEntry("ArrayBuffer"),
45174517
interfaceEntry("ArrayBufferTypes"),
45184518
typeEntry("ArrayBufferLike"),
45194519
interfaceEntry("ArrayBufferConstructor"),
45204520
interfaceEntry("ArrayBufferView"),
4521-
constEntry("DataView"),
4521+
varEntry("DataView"),
45224522
interfaceEntry("DataViewConstructor"),
4523-
constEntry("Int8Array"),
4523+
varEntry("Int8Array"),
45244524
interfaceEntry("Int8ArrayConstructor"),
4525-
constEntry("Uint8Array"),
4525+
varEntry("Uint8Array"),
45264526
interfaceEntry("Uint8ArrayConstructor"),
4527-
constEntry("Uint8ClampedArray"),
4527+
varEntry("Uint8ClampedArray"),
45284528
interfaceEntry("Uint8ClampedArrayConstructor"),
4529-
constEntry("Int16Array"),
4529+
varEntry("Int16Array"),
45304530
interfaceEntry("Int16ArrayConstructor"),
4531-
constEntry("Uint16Array"),
4531+
varEntry("Uint16Array"),
45324532
interfaceEntry("Uint16ArrayConstructor"),
4533-
constEntry("Int32Array"),
4533+
varEntry("Int32Array"),
45344534
interfaceEntry("Int32ArrayConstructor"),
4535-
constEntry("Uint32Array"),
4535+
varEntry("Uint32Array"),
45364536
interfaceEntry("Uint32ArrayConstructor"),
4537-
constEntry("Float32Array"),
4537+
varEntry("Float32Array"),
45384538
interfaceEntry("Float32ArrayConstructor"),
4539-
constEntry("Float64Array"),
4539+
varEntry("Float64Array"),
45404540
interfaceEntry("Float64ArrayConstructor"),
45414541
moduleEntry("Intl"),
45424542
];
@@ -4744,36 +4744,36 @@ namespace FourSlashInterface {
47444744
functionEntry("encodeURIComponent"),
47454745
functionEntry("escape"),
47464746
functionEntry("unescape"),
4747-
constEntry("NaN"),
4748-
constEntry("Infinity"),
4749-
constEntry("Object"),
4750-
constEntry("Function"),
4751-
constEntry("String"),
4752-
constEntry("Boolean"),
4753-
constEntry("Number"),
4754-
constEntry("Math"),
4755-
constEntry("Date"),
4756-
constEntry("RegExp"),
4757-
constEntry("Error"),
4758-
constEntry("EvalError"),
4759-
constEntry("RangeError"),
4760-
constEntry("ReferenceError"),
4761-
constEntry("SyntaxError"),
4762-
constEntry("TypeError"),
4763-
constEntry("URIError"),
4764-
constEntry("JSON"),
4765-
constEntry("Array"),
4766-
constEntry("ArrayBuffer"),
4767-
constEntry("DataView"),
4768-
constEntry("Int8Array"),
4769-
constEntry("Uint8Array"),
4770-
constEntry("Uint8ClampedArray"),
4771-
constEntry("Int16Array"),
4772-
constEntry("Uint16Array"),
4773-
constEntry("Int32Array"),
4774-
constEntry("Uint32Array"),
4775-
constEntry("Float32Array"),
4776-
constEntry("Float64Array"),
4747+
varEntry("NaN"),
4748+
varEntry("Infinity"),
4749+
varEntry("Object"),
4750+
varEntry("Function"),
4751+
varEntry("String"),
4752+
varEntry("Boolean"),
4753+
varEntry("Number"),
4754+
varEntry("Math"),
4755+
varEntry("Date"),
4756+
varEntry("RegExp"),
4757+
varEntry("Error"),
4758+
varEntry("EvalError"),
4759+
varEntry("RangeError"),
4760+
varEntry("ReferenceError"),
4761+
varEntry("SyntaxError"),
4762+
varEntry("TypeError"),
4763+
varEntry("URIError"),
4764+
varEntry("JSON"),
4765+
varEntry("Array"),
4766+
varEntry("ArrayBuffer"),
4767+
varEntry("DataView"),
4768+
varEntry("Int8Array"),
4769+
varEntry("Uint8Array"),
4770+
varEntry("Uint8ClampedArray"),
4771+
varEntry("Int16Array"),
4772+
varEntry("Uint16Array"),
4773+
varEntry("Int32Array"),
4774+
varEntry("Uint32Array"),
4775+
varEntry("Float32Array"),
4776+
varEntry("Float64Array"),
47774777
moduleEntry("Intl"),
47784778
];
47794779

0 commit comments

Comments
 (0)