From 95862880fb901ba0e3d3a9d8c6f008a181192b03 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 8 Mar 2018 09:30:25 -0800 Subject: [PATCH] Filter symbol property names out of index signature assignability checks (#22398) --- src/compiler/checker.ts | 9 +++-- ...IndexInObjectWithIndexSignature.errors.txt | 21 +++++++++++ ...olAllowsIndexInObjectWithIndexSignature.js | 21 +++++++++++ ...owsIndexInObjectWithIndexSignature.symbols | 29 +++++++++++++++ ...llowsIndexInObjectWithIndexSignature.types | 35 +++++++++++++++++++ ...olAllowsIndexInObjectWithIndexSignature.ts | 11 ++++++ 6 files changed, 124 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/uniqueSymbolAllowsIndexInObjectWithIndexSignature.errors.txt create mode 100644 tests/baselines/reference/uniqueSymbolAllowsIndexInObjectWithIndexSignature.js create mode 100644 tests/baselines/reference/uniqueSymbolAllowsIndexInObjectWithIndexSignature.symbols create mode 100644 tests/baselines/reference/uniqueSymbolAllowsIndexInObjectWithIndexSignature.types create mode 100644 tests/cases/compiler/uniqueSymbolAllowsIndexInObjectWithIndexSignature.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index babac08051..6ed61d0a5d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8008,10 +8008,10 @@ namespace ts { } function getLiteralTypeFromPropertyName(prop: Symbol) { - const links = getSymbolLinks(prop); + const links = getSymbolLinks(getLateBoundSymbol(prop)); if (!links.nameType) { if (links.target) { - Debug.assert(links.target.escapedName === prop.escapedName, "Target symbol and symbol do not have the same name"); + Debug.assert(links.target.escapedName === prop.escapedName || links.target.escapedName === InternalSymbolName.Computed, "Target symbol and symbol do not have the same name"); links.nameType = getLiteralTypeFromPropertyName(links.target); } else { @@ -10558,6 +10558,11 @@ namespace ts { if (isIgnoredJsxProperty(source, prop, /*targetMemberType*/ undefined)) { continue; } + // Skip over symbol-named members + const nameType = getLiteralTypeFromPropertyName(prop); + if (nameType !== undefined && !(isRelatedTo(nameType, stringType) || isRelatedTo(nameType, numberType))) { + continue; + } if (kind === IndexKind.String || isNumericLiteralName(prop.escapedName)) { const related = isRelatedTo(getTypeOfSymbol(prop), target, reportErrors); if (!related) { diff --git a/tests/baselines/reference/uniqueSymbolAllowsIndexInObjectWithIndexSignature.errors.txt b/tests/baselines/reference/uniqueSymbolAllowsIndexInObjectWithIndexSignature.errors.txt new file mode 100644 index 0000000000..eca289e819 --- /dev/null +++ b/tests/baselines/reference/uniqueSymbolAllowsIndexInObjectWithIndexSignature.errors.txt @@ -0,0 +1,21 @@ +tests/cases/compiler/uniqueSymbolAllowsIndexInObjectWithIndexSignature.ts(10,5): error TS2322: Type '{ [SYM]: "str"; }' is not assignable to type 'I'. + Types of property '[SYM]' are incompatible. + Type '"str"' is not assignable to type '"sym"'. + + +==== tests/cases/compiler/uniqueSymbolAllowsIndexInObjectWithIndexSignature.ts (1 errors) ==== + // https://github.com/Microsoft/TypeScript/issues/21962 + export const SYM = Symbol('a unique symbol'); + + export interface I { + [SYM]: 'sym'; + [x: string]: 'str'; + } + + let a: I = {[SYM]: 'sym'}; // Expect ok + let b: I = {[SYM]: 'str'}; // Expect error + ~ +!!! error TS2322: Type '{ [SYM]: "str"; }' is not assignable to type 'I'. +!!! error TS2322: Types of property '[SYM]' are incompatible. +!!! error TS2322: Type '"str"' is not assignable to type '"sym"'. + \ No newline at end of file diff --git a/tests/baselines/reference/uniqueSymbolAllowsIndexInObjectWithIndexSignature.js b/tests/baselines/reference/uniqueSymbolAllowsIndexInObjectWithIndexSignature.js new file mode 100644 index 0000000000..21a6d85ac2 --- /dev/null +++ b/tests/baselines/reference/uniqueSymbolAllowsIndexInObjectWithIndexSignature.js @@ -0,0 +1,21 @@ +//// [uniqueSymbolAllowsIndexInObjectWithIndexSignature.ts] +// https://github.com/Microsoft/TypeScript/issues/21962 +export const SYM = Symbol('a unique symbol'); + +export interface I { + [SYM]: 'sym'; + [x: string]: 'str'; +} + +let a: I = {[SYM]: 'sym'}; // Expect ok +let b: I = {[SYM]: 'str'}; // Expect error + + +//// [uniqueSymbolAllowsIndexInObjectWithIndexSignature.js] +"use strict"; +exports.__esModule = true; +// https://github.com/Microsoft/TypeScript/issues/21962 +exports.SYM = Symbol('a unique symbol'); +var a = (_a = {}, _a[exports.SYM] = 'sym', _a); // Expect ok +var b = (_b = {}, _b[exports.SYM] = 'str', _b); // Expect error +var _a, _b; diff --git a/tests/baselines/reference/uniqueSymbolAllowsIndexInObjectWithIndexSignature.symbols b/tests/baselines/reference/uniqueSymbolAllowsIndexInObjectWithIndexSignature.symbols new file mode 100644 index 0000000000..fc3ba1ced5 --- /dev/null +++ b/tests/baselines/reference/uniqueSymbolAllowsIndexInObjectWithIndexSignature.symbols @@ -0,0 +1,29 @@ +=== tests/cases/compiler/uniqueSymbolAllowsIndexInObjectWithIndexSignature.ts === +// https://github.com/Microsoft/TypeScript/issues/21962 +export const SYM = Symbol('a unique symbol'); +>SYM : Symbol(SYM, Decl(uniqueSymbolAllowsIndexInObjectWithIndexSignature.ts, 1, 12)) +>Symbol : Symbol(Symbol, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --)) + +export interface I { +>I : Symbol(I, Decl(uniqueSymbolAllowsIndexInObjectWithIndexSignature.ts, 1, 45)) + + [SYM]: 'sym'; +>[SYM] : Symbol(I[SYM], Decl(uniqueSymbolAllowsIndexInObjectWithIndexSignature.ts, 3, 20)) +>SYM : Symbol(SYM, Decl(uniqueSymbolAllowsIndexInObjectWithIndexSignature.ts, 1, 12)) + + [x: string]: 'str'; +>x : Symbol(x, Decl(uniqueSymbolAllowsIndexInObjectWithIndexSignature.ts, 5, 3)) +} + +let a: I = {[SYM]: 'sym'}; // Expect ok +>a : Symbol(a, Decl(uniqueSymbolAllowsIndexInObjectWithIndexSignature.ts, 8, 3)) +>I : Symbol(I, Decl(uniqueSymbolAllowsIndexInObjectWithIndexSignature.ts, 1, 45)) +>[SYM] : Symbol([SYM], Decl(uniqueSymbolAllowsIndexInObjectWithIndexSignature.ts, 8, 12)) +>SYM : Symbol(SYM, Decl(uniqueSymbolAllowsIndexInObjectWithIndexSignature.ts, 1, 12)) + +let b: I = {[SYM]: 'str'}; // Expect error +>b : Symbol(b, Decl(uniqueSymbolAllowsIndexInObjectWithIndexSignature.ts, 9, 3)) +>I : Symbol(I, Decl(uniqueSymbolAllowsIndexInObjectWithIndexSignature.ts, 1, 45)) +>[SYM] : Symbol([SYM], Decl(uniqueSymbolAllowsIndexInObjectWithIndexSignature.ts, 9, 12)) +>SYM : Symbol(SYM, Decl(uniqueSymbolAllowsIndexInObjectWithIndexSignature.ts, 1, 12)) + diff --git a/tests/baselines/reference/uniqueSymbolAllowsIndexInObjectWithIndexSignature.types b/tests/baselines/reference/uniqueSymbolAllowsIndexInObjectWithIndexSignature.types new file mode 100644 index 0000000000..be4cafe5e8 --- /dev/null +++ b/tests/baselines/reference/uniqueSymbolAllowsIndexInObjectWithIndexSignature.types @@ -0,0 +1,35 @@ +=== tests/cases/compiler/uniqueSymbolAllowsIndexInObjectWithIndexSignature.ts === +// https://github.com/Microsoft/TypeScript/issues/21962 +export const SYM = Symbol('a unique symbol'); +>SYM : unique symbol +>Symbol('a unique symbol') : unique symbol +>Symbol : SymbolConstructor +>'a unique symbol' : "a unique symbol" + +export interface I { +>I : I + + [SYM]: 'sym'; +>[SYM] : "sym" +>SYM : unique symbol + + [x: string]: 'str'; +>x : string +} + +let a: I = {[SYM]: 'sym'}; // Expect ok +>a : I +>I : I +>{[SYM]: 'sym'} : { [SYM]: "sym"; } +>[SYM] : "sym" +>SYM : unique symbol +>'sym' : "sym" + +let b: I = {[SYM]: 'str'}; // Expect error +>b : I +>I : I +>{[SYM]: 'str'} : { [SYM]: "str"; } +>[SYM] : "str" +>SYM : unique symbol +>'str' : "str" + diff --git a/tests/cases/compiler/uniqueSymbolAllowsIndexInObjectWithIndexSignature.ts b/tests/cases/compiler/uniqueSymbolAllowsIndexInObjectWithIndexSignature.ts new file mode 100644 index 0000000000..0550c7b8d9 --- /dev/null +++ b/tests/cases/compiler/uniqueSymbolAllowsIndexInObjectWithIndexSignature.ts @@ -0,0 +1,11 @@ +// @lib: es6 +// https://github.com/Microsoft/TypeScript/issues/21962 +export const SYM = Symbol('a unique symbol'); + +export interface I { + [SYM]: 'sym'; + [x: string]: 'str'; +} + +let a: I = {[SYM]: 'sym'}; // Expect ok +let b: I = {[SYM]: 'str'}; // Expect error