Produce wide index signatures from the spread of an index signature

This commit is contained in:
Andrew Branch 2023-11-16 16:44:24 -08:00
parent 8b43f5bbe3
commit d088733b24
No known key found for this signature in database
GPG Key ID: 22CCA4B120C427D2
5 changed files with 117 additions and 2 deletions

View File

@ -13435,6 +13435,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return emptyArray;
}
function getSpreadIndexInfos(left: Type, right: Type): IndexInfo[] {
const rightInfos = getIndexInfosOfType(right);
if (!rightInfos.length) return emptyArray;
const leftInfos = getIndexInfosOfType(left);
const leftProperties = getPropertiesOfType(left);
const result: IndexInfo[] = [];
for (const rightInfo of rightInfos) {
const indexType = rightInfo.keyType;
const leftInfo = findIndexInfo(leftInfos, indexType);
const types = leftInfo ? [leftInfo.type, rightInfo.type] : [rightInfo.type];
for (const prop of leftProperties) {
if (isApplicableIndexType(getNameTypeOfPropertyName(prop.escapedName), indexType)) {
types.push(getTypeOfSymbol(prop));
}
}
result.push(createIndexInfo(indexType, getUnionType(types), leftInfo && leftInfo.isReadonly || rightInfo.isReadonly));
}
return result;
}
function resolveUnionTypeMembers(type: UnionType) {
// The members and properties collections are empty for union types. To get all properties of a union
// type use getPropertiesOfType (only the language service uses this).
@ -14888,7 +14908,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
function getApplicableIndexInfoForName(type: Type, name: __String): IndexInfo | undefined {
return getApplicableIndexInfo(type, isLateBoundName(name) ? esSymbolType : getStringLiteralType(unescapeLeadingUnderscores(name)));
return getApplicableIndexInfo(type, getNameTypeOfPropertyName(name));
}
function getNameTypeOfPropertyName(name: __String): Type {
return isLateBoundName(name) ? esSymbolType : getStringLiteralType(unescapeLeadingUnderscores(name));
}
// Return list of type parameters with duplicates removed (duplicate identifier errors are generated in the actual
@ -18793,7 +18817,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const members = createSymbolTable();
const skippedPrivateMembers = new Set<__String>();
const indexInfos = left === emptyObjectType ? getIndexInfosOfType(right) : getUnionIndexInfos([left, right]);
const indexInfos = left === emptyObjectType ? getIndexInfosOfType(right) : getSpreadIndexInfos(left, right);
for (const rightProp of getPropertiesOfType(right)) {
if (getDeclarationModifierFlagsFromSymbol(rightProp) & (ModifierFlags.Private | ModifierFlags.Protected)) {

View File

@ -0,0 +1,15 @@
//// [tests/cases/compiler/spreadIndexSignature.ts] ////
//// [spreadIndexSignature.ts]
declare const strings: Record<string, string>;
declare const symbols: Record<symbol, string>;
const o1 = { a: 1, ...strings };
const o2 = { [Symbol.iterator]: 1, ...strings };
const o3 = { [Symbol.iterator]: 1, ...symbols };
//// [spreadIndexSignature.js]
const o1 = { a: 1, ...strings };
const o2 = { [Symbol.iterator]: 1, ...strings };
const o3 = { [Symbol.iterator]: 1, ...symbols };

View File

@ -0,0 +1,32 @@
//// [tests/cases/compiler/spreadIndexSignature.ts] ////
=== spreadIndexSignature.ts ===
declare const strings: Record<string, string>;
>strings : Symbol(strings, Decl(spreadIndexSignature.ts, 0, 13))
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
declare const symbols: Record<symbol, string>;
>symbols : Symbol(symbols, Decl(spreadIndexSignature.ts, 1, 13))
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
const o1 = { a: 1, ...strings };
>o1 : Symbol(o1, Decl(spreadIndexSignature.ts, 3, 5))
>a : Symbol(a, Decl(spreadIndexSignature.ts, 3, 12))
>strings : Symbol(strings, Decl(spreadIndexSignature.ts, 0, 13))
const o2 = { [Symbol.iterator]: 1, ...strings };
>o2 : Symbol(o2, Decl(spreadIndexSignature.ts, 4, 5))
>[Symbol.iterator] : Symbol([Symbol.iterator], Decl(spreadIndexSignature.ts, 4, 12))
>Symbol.iterator : Symbol(SymbolConstructor.iterator, Decl(lib.es2015.iterable.d.ts, --, --))
>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, --, --))
>iterator : Symbol(SymbolConstructor.iterator, Decl(lib.es2015.iterable.d.ts, --, --))
>strings : Symbol(strings, Decl(spreadIndexSignature.ts, 0, 13))
const o3 = { [Symbol.iterator]: 1, ...symbols };
>o3 : Symbol(o3, Decl(spreadIndexSignature.ts, 5, 5))
>[Symbol.iterator] : Symbol([Symbol.iterator], Decl(spreadIndexSignature.ts, 5, 12))
>Symbol.iterator : Symbol(SymbolConstructor.iterator, Decl(lib.es2015.iterable.d.ts, --, --))
>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, --, --))
>iterator : Symbol(SymbolConstructor.iterator, Decl(lib.es2015.iterable.d.ts, --, --))
>symbols : Symbol(symbols, Decl(spreadIndexSignature.ts, 1, 13))

View File

@ -0,0 +1,36 @@
//// [tests/cases/compiler/spreadIndexSignature.ts] ////
=== spreadIndexSignature.ts ===
declare const strings: Record<string, string>;
>strings : Record<string, string>
declare const symbols: Record<symbol, string>;
>symbols : Record<symbol, string>
const o1 = { a: 1, ...strings };
>o1 : { [x: string]: string | number; a: number; }
>{ a: 1, ...strings } : { [x: string]: string | number; a: number; }
>a : number
>1 : 1
>strings : Record<string, string>
const o2 = { [Symbol.iterator]: 1, ...strings };
>o2 : { [x: string]: string; [Symbol.iterator]: number; }
>{ [Symbol.iterator]: 1, ...strings } : { [x: string]: string; [Symbol.iterator]: number; }
>[Symbol.iterator] : number
>Symbol.iterator : unique symbol
>Symbol : SymbolConstructor
>iterator : unique symbol
>1 : 1
>strings : Record<string, string>
const o3 = { [Symbol.iterator]: 1, ...symbols };
>o3 : { [x: symbol]: string | number; [Symbol.iterator]: number; }
>{ [Symbol.iterator]: 1, ...symbols } : { [x: symbol]: string | number; [Symbol.iterator]: number; }
>[Symbol.iterator] : number
>Symbol.iterator : unique symbol
>Symbol : SymbolConstructor
>iterator : unique symbol
>1 : 1
>symbols : Record<symbol, string>

View File

@ -0,0 +1,8 @@
// @target: esnext
declare const strings: Record<string, string>;
declare const symbols: Record<symbol, string>;
const o1 = { a: 1, ...strings };
const o2 = { [Symbol.iterator]: 1, ...strings };
const o3 = { [Symbol.iterator]: 1, ...symbols };