Validate symbol-named properties against symbol index signatures (#44815)

* Validate symbols against both symbol and string index signatures

* Add tests

* Accept new baselines
This commit is contained in:
Anders Hejlsberg
2021-06-29 14:53:07 -07:00
committed by GitHub
parent 114f68cd3d
commit 4c19873b64
6 changed files with 155 additions and 2 deletions

View File

@@ -12106,7 +12106,7 @@ namespace ts {
}
function getApplicableIndexInfoForName(type: Type, name: __String): IndexInfo | undefined {
return getApplicableIndexInfo(type, getStringLiteralType(unescapeLeadingUnderscores(name)));
return getApplicableIndexInfo(type, isLateBoundName(name) ? esSymbolType : getStringLiteralType(unescapeLeadingUnderscores(name)));
}
// Return list of type parameters with duplicates removed (duplicate identifier errors are generated in the actual
@@ -27121,8 +27121,12 @@ namespace ts {
*/
function isKnownProperty(targetType: Type, name: __String, isComparingJsxAttributes: boolean): boolean {
if (targetType.flags & TypeFlags.Object) {
// For backwards compatibility a symbol-named property is satisfied by a string index signature. This
// is incorrect and inconsistent with element access expressions, where it is an error, so eventually
// we should remove this exception.
if (getPropertyOfObjectType(targetType, name) ||
getApplicableIndexInfoForName(targetType, name) ||
isLateBoundName(name) && getIndexInfoOfType(targetType, stringType) ||
isComparingJsxAttributes && !isUnhyphenatedJsxName(name)) {
// For JSXAttributes, if the attribute has a hyphenated name, consider that the attribute to be known.
return true;

View File

@@ -68,9 +68,11 @@ tests/cases/conformance/types/members/indexSignatures1.ts(281,35): error TS2322:
Object literal may only specify known properties, and ''someKey'' does not exist in type 'PseudoDeclaration'.
tests/cases/conformance/types/members/indexSignatures1.ts(286,7): error TS2322: Type '"two"' is not assignable to type '`/${string}`'.
tests/cases/conformance/types/members/indexSignatures1.ts(289,7): error TS2322: Type 'number' is not assignable to type 'PathsObject'.
tests/cases/conformance/types/members/indexSignatures1.ts(312,43): error TS2322: Type '{ [sym]: string; }' is not assignable to type '{ [key: number]: string; }'.
Object literal may only specify known properties, and '[sym]' does not exist in type '{ [key: number]: string; }'.
==== tests/cases/conformance/types/members/indexSignatures1.ts (49 errors) ====
==== tests/cases/conformance/types/members/indexSignatures1.ts (50 errors) ====
// Symbol index signature checking
const sym = Symbol();
@@ -488,4 +490,21 @@ tests/cases/conformance/types/members/indexSignatures1.ts(289,7): error TS2322:
const a: A = { [id]: 'test' }
let aid = a[id];
// Repro from #44793
interface AA {
a?: string;
b?: number;
[key: symbol]: string;
}
const aa: AA = { [sym]: '123' };
const obj1: { [key: symbol]: string } = { [sym]: 'hello '};
const obj2: { [key: string]: string } = { [sym]: 'hello '}; // Permitted for backwards compatibility
const obj3: { [key: number]: string } = { [sym]: 'hello '}; // Error
~~~~~~~~~~~~~~~
!!! error TS2322: Type '{ [sym]: string; }' is not assignable to type '{ [key: number]: string; }'.
!!! error TS2322: Object literal may only specify known properties, and '[sym]' does not exist in type '{ [key: number]: string; }'.

View File

@@ -297,6 +297,20 @@ type A = Record<IdType, string>;
const a: A = { [id]: 'test' }
let aid = a[id];
// Repro from #44793
interface AA {
a?: string;
b?: number;
[key: symbol]: string;
}
const aa: AA = { [sym]: '123' };
const obj1: { [key: symbol]: string } = { [sym]: 'hello '};
const obj2: { [key: string]: string } = { [sym]: 'hello '}; // Permitted for backwards compatibility
const obj3: { [key: number]: string } = { [sym]: 'hello '}; // Error
//// [indexSignatures1.js]
@@ -457,6 +471,10 @@ const pathObject = 123; // Error
const id = '0000-0000-0000-0001';
const a = { [id]: 'test' };
let aid = a[id];
const aa = { [sym]: '123' };
const obj1 = { [sym]: 'hello ' };
const obj2 = { [sym]: 'hello ' }; // Permitted for backwards compatibility
const obj3 = { [sym]: 'hello ' }; // Error
//// [indexSignatures1.d.ts]
@@ -627,3 +645,18 @@ declare const id: IdType;
declare type A = Record<IdType, string>;
declare const a: A;
declare let aid: string;
interface AA {
a?: string;
b?: number;
[key: symbol]: string;
}
declare const aa: AA;
declare const obj1: {
[key: symbol]: string;
};
declare const obj2: {
[key: string]: string;
};
declare const obj3: {
[key: number]: string;
};

View File

@@ -860,3 +860,42 @@ let aid = a[id];
>a : Symbol(a, Decl(indexSignatures1.ts, 295, 5))
>id : Symbol(id, Decl(indexSignatures1.ts, 291, 5))
// Repro from #44793
interface AA {
>AA : Symbol(AA, Decl(indexSignatures1.ts, 297, 16))
a?: string;
>a : Symbol(AA.a, Decl(indexSignatures1.ts, 301, 14))
b?: number;
>b : Symbol(AA.b, Decl(indexSignatures1.ts, 302, 15))
[key: symbol]: string;
>key : Symbol(key, Decl(indexSignatures1.ts, 304, 5))
}
const aa: AA = { [sym]: '123' };
>aa : Symbol(aa, Decl(indexSignatures1.ts, 307, 5))
>AA : Symbol(AA, Decl(indexSignatures1.ts, 297, 16))
>[sym] : Symbol([sym], Decl(indexSignatures1.ts, 307, 16))
>sym : Symbol(sym, Decl(indexSignatures1.ts, 2, 5))
const obj1: { [key: symbol]: string } = { [sym]: 'hello '};
>obj1 : Symbol(obj1, Decl(indexSignatures1.ts, 309, 5))
>key : Symbol(key, Decl(indexSignatures1.ts, 309, 15))
>[sym] : Symbol([sym], Decl(indexSignatures1.ts, 309, 41))
>sym : Symbol(sym, Decl(indexSignatures1.ts, 2, 5))
const obj2: { [key: string]: string } = { [sym]: 'hello '}; // Permitted for backwards compatibility
>obj2 : Symbol(obj2, Decl(indexSignatures1.ts, 310, 5))
>key : Symbol(key, Decl(indexSignatures1.ts, 310, 15))
>[sym] : Symbol([sym], Decl(indexSignatures1.ts, 310, 41))
>sym : Symbol(sym, Decl(indexSignatures1.ts, 2, 5))
const obj3: { [key: number]: string } = { [sym]: 'hello '}; // Error
>obj3 : Symbol(obj3, Decl(indexSignatures1.ts, 311, 5))
>key : Symbol(key, Decl(indexSignatures1.ts, 311, 15))
>[sym] : Symbol([sym], Decl(indexSignatures1.ts, 311, 41))
>sym : Symbol(sym, Decl(indexSignatures1.ts, 2, 5))

View File

@@ -1007,3 +1007,47 @@ let aid = a[id];
>a : A
>id : `${number}-${number}-${number}-${number}`
// Repro from #44793
interface AA {
a?: string;
>a : string | undefined
b?: number;
>b : number | undefined
[key: symbol]: string;
>key : symbol
}
const aa: AA = { [sym]: '123' };
>aa : AA
>{ [sym]: '123' } : { [sym]: string; }
>[sym] : string
>sym : unique symbol
>'123' : "123"
const obj1: { [key: symbol]: string } = { [sym]: 'hello '};
>obj1 : { [key: symbol]: string; }
>key : symbol
>{ [sym]: 'hello '} : { [sym]: string; }
>[sym] : string
>sym : unique symbol
>'hello ' : "hello "
const obj2: { [key: string]: string } = { [sym]: 'hello '}; // Permitted for backwards compatibility
>obj2 : { [key: string]: string; }
>key : string
>{ [sym]: 'hello '} : { [sym]: string; }
>[sym] : string
>sym : unique symbol
>'hello ' : "hello "
const obj3: { [key: number]: string } = { [sym]: 'hello '}; // Error
>obj3 : { [key: number]: string; }
>key : number
>{ [sym]: 'hello '} : { [sym]: string; }
>[sym] : string
>sym : unique symbol
>'hello ' : "hello "

View File

@@ -300,3 +300,17 @@ type A = Record<IdType, string>;
const a: A = { [id]: 'test' }
let aid = a[id];
// Repro from #44793
interface AA {
a?: string;
b?: number;
[key: symbol]: string;
}
const aa: AA = { [sym]: '123' };
const obj1: { [key: symbol]: string } = { [sym]: 'hello '};
const obj2: { [key: string]: string } = { [sym]: 'hello '}; // Permitted for backwards compatibility
const obj3: { [key: number]: string } = { [sym]: 'hello '}; // Error