Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10630,6 +10630,10 @@ namespace ts {
return type;
}

function getIsLateCheckFlag(s: Symbol): CheckFlags {
return getCheckFlags(s) & CheckFlags.Late;
}

/** Resolve the members of a mapped type { [P in K]: T } */
function resolveMappedTypeMembers(type: MappedType) {
const members: SymbolTable = createSymbolTable();
Expand Down Expand Up @@ -10688,8 +10692,9 @@ namespace ts {
const isReadonly = !!(templateModifiers & MappedTypeModifiers.IncludeReadonly ||
!(templateModifiers & MappedTypeModifiers.ExcludeReadonly) && modifiersProp && isReadonlySymbol(modifiersProp));
const stripOptional = strictNullChecks && !isOptional && modifiersProp && modifiersProp.flags & SymbolFlags.Optional;
const lateFlag: CheckFlags = modifiersProp ? getIsLateCheckFlag(modifiersProp) : 0;
const prop = <MappedSymbol>createSymbol(SymbolFlags.Property | (isOptional ? SymbolFlags.Optional : 0), propName,
CheckFlags.Mapped | (isReadonly ? CheckFlags.Readonly : 0) | (stripOptional ? CheckFlags.StripOptional : 0));
lateFlag | CheckFlags.Mapped | (isReadonly ? CheckFlags.Readonly : 0) | (stripOptional ? CheckFlags.StripOptional : 0));
prop.mappedType = type;
prop.nameType = propNameType;
prop.keyType = keyType;
Expand Down Expand Up @@ -14666,7 +14671,7 @@ namespace ts {
else if (isSpreadableProperty(prop)) {
const isSetonlyAccessor = prop.flags & SymbolFlags.SetAccessor && !(prop.flags & SymbolFlags.GetAccessor);
const flags = SymbolFlags.Property | SymbolFlags.Optional;
const result = createSymbol(flags, prop.escapedName, readonly ? CheckFlags.Readonly : 0);
const result = createSymbol(flags, prop.escapedName, getIsLateCheckFlag(prop) | (readonly ? CheckFlags.Readonly : 0));
result.type = isSetonlyAccessor ? undefinedType : getTypeOfSymbol(prop);
result.declarations = prop.declarations;
result.nameType = getSymbolLinks(prop).nameType;
Expand Down Expand Up @@ -14814,7 +14819,7 @@ namespace ts {
return prop;
}
const flags = SymbolFlags.Property | (prop.flags & SymbolFlags.Optional);
const result = createSymbol(flags, prop.escapedName, readonly ? CheckFlags.Readonly : 0);
const result = createSymbol(flags, prop.escapedName, getIsLateCheckFlag(prop) | (readonly ? CheckFlags.Readonly : 0));
result.type = isSetonlyAccessor ? undefinedType : getTypeOfSymbol(prop);
result.declarations = prop.declarations;
result.nameType = getSymbolLinks(prop).nameType;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
tests/cases/compiler/index.ts(3,14): error TS4023: Exported variable 'spread' has or is using name 'SYMBOL' from external module "tests/cases/compiler/bug" but cannot be named.


==== tests/cases/compiler/bug.ts (0 errors) ====
export const SYMBOL = Symbol()

export interface Interface {
readonly [SYMBOL]: string; // remove readonly and @showEmit to see the expected error
}

export function createInstance(): Interface {
return {
[SYMBOL]: ''
}
}

==== tests/cases/compiler/index.ts (1 errors) ====
import { createInstance } from './bug'

export const spread = {
~~~~~~
!!! error TS4023: Exported variable 'spread' has or is using name 'SYMBOL' from external module "tests/cases/compiler/bug" but cannot be named.
...createInstance(),
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
//// [tests/cases/compiler/declarationEmitReadonlyComputedProperty.ts] ////

//// [bug.ts]
export const SYMBOL = Symbol()

export interface Interface {
readonly [SYMBOL]: string; // remove readonly and @showEmit to see the expected error
}

export function createInstance(): Interface {
return {
[SYMBOL]: ''
}
}

//// [index.ts]
import { createInstance } from './bug'

export const spread = {
...createInstance(),
}

//// [bug.js]
"use strict";
exports.__esModule = true;
exports.createInstance = exports.SYMBOL = void 0;
exports.SYMBOL = Symbol();
function createInstance() {
var _a;
return _a = {},
_a[exports.SYMBOL] = '',
_a;
}
exports.createInstance = createInstance;
//// [index.js]
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
exports.__esModule = true;
exports.spread = void 0;
var bug_1 = require("./bug");
exports.spread = __assign({}, bug_1.createInstance());


//// [bug.d.ts]
export declare const SYMBOL: unique symbol;
export interface Interface {
readonly [SYMBOL]: string;
}
export declare function createInstance(): Interface;
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
=== tests/cases/compiler/bug.ts ===
export const SYMBOL = Symbol()
>SYMBOL : Symbol(SYMBOL, Decl(bug.ts, 0, 12))
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))

export interface Interface {
>Interface : Symbol(Interface, Decl(bug.ts, 0, 30))

readonly [SYMBOL]: string; // remove readonly and @showEmit to see the expected error
>[SYMBOL] : Symbol(Interface[SYMBOL], Decl(bug.ts, 2, 28))
>SYMBOL : Symbol(SYMBOL, Decl(bug.ts, 0, 12))
}

export function createInstance(): Interface {
>createInstance : Symbol(createInstance, Decl(bug.ts, 4, 1))
>Interface : Symbol(Interface, Decl(bug.ts, 0, 30))

return {
[SYMBOL]: ''
>[SYMBOL] : Symbol([SYMBOL], Decl(bug.ts, 7, 10))
>SYMBOL : Symbol(SYMBOL, Decl(bug.ts, 0, 12))
}
}

=== tests/cases/compiler/index.ts ===
import { createInstance } from './bug'
>createInstance : Symbol(createInstance, Decl(index.ts, 0, 8))

export const spread = {
>spread : Symbol(spread, Decl(index.ts, 2, 12))

...createInstance(),
>createInstance : Symbol(createInstance, Decl(index.ts, 0, 8))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
=== tests/cases/compiler/bug.ts ===
export const SYMBOL = Symbol()
>SYMBOL : unique symbol
>Symbol() : unique symbol
>Symbol : SymbolConstructor

export interface Interface {
readonly [SYMBOL]: string; // remove readonly and @showEmit to see the expected error
>[SYMBOL] : string
>SYMBOL : unique symbol
}

export function createInstance(): Interface {
>createInstance : () => Interface

return {
>{ [SYMBOL]: '' } : { [SYMBOL]: string; }

[SYMBOL]: ''
>[SYMBOL] : string
>SYMBOL : unique symbol
>'' : ""
}
}

=== tests/cases/compiler/index.ts ===
import { createInstance } from './bug'
>createInstance : () => import("tests/cases/compiler/bug").Interface

export const spread = {
>spread : { [SYMBOL]: string; }
>{ ...createInstance(),} : { [SYMBOL]: string; }

...createInstance(),
>createInstance() : import("tests/cases/compiler/bug").Interface
>createInstance : () => import("tests/cases/compiler/bug").Interface
}
22 changes: 22 additions & 0 deletions tests/cases/compiler/declarationEmitReadonlyComputedProperty.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// @declaration: true
// @lib: es2015

// @filename: bug.ts
export const SYMBOL = Symbol()

export interface Interface {
readonly [SYMBOL]: string; // remove readonly and @showEmit to see the expected error
}

export function createInstance(): Interface {
return {
[SYMBOL]: ''
}
}

// @filename: index.ts
import { createInstance } from './bug'

export const spread = {
...createInstance(),
}