mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 21:53:42 -06:00
Merge pull request #18965 from Microsoft/set-symbol-on-union-of-spreads
Set symbol on union that is returned from `getSpreadType`
This commit is contained in:
commit
461e29bbd8
@ -7878,7 +7878,7 @@ namespace ts {
|
||||
* this function should be called in a left folding style, with left = previous result of getSpreadType
|
||||
* and right = the new element to be spread.
|
||||
*/
|
||||
function getSpreadType(left: Type, right: Type): Type {
|
||||
function getSpreadType(left: Type, right: Type, symbol: Symbol, propagatedFlags: TypeFlags): Type {
|
||||
if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) {
|
||||
return anyType;
|
||||
}
|
||||
@ -7889,10 +7889,10 @@ namespace ts {
|
||||
return left;
|
||||
}
|
||||
if (left.flags & TypeFlags.Union) {
|
||||
return mapType(left, t => getSpreadType(t, right));
|
||||
return mapType(left, t => getSpreadType(t, right, symbol, propagatedFlags));
|
||||
}
|
||||
if (right.flags & TypeFlags.Union) {
|
||||
return mapType(right, t => getSpreadType(left, t));
|
||||
return mapType(right, t => getSpreadType(left, t, symbol, propagatedFlags));
|
||||
}
|
||||
if (right.flags & TypeFlags.NonPrimitive) {
|
||||
return nonPrimitiveType;
|
||||
@ -7950,7 +7950,13 @@ namespace ts {
|
||||
members.set(leftProp.escapedName, getNonReadonlySymbol(leftProp));
|
||||
}
|
||||
}
|
||||
return createAnonymousType(undefined, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
|
||||
|
||||
const spread = createAnonymousType(undefined, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
|
||||
spread.flags |= propagatedFlags;
|
||||
spread.flags |= TypeFlags.FreshLiteral;
|
||||
(spread as ObjectType).objectFlags |= ObjectFlags.ObjectLiteral;
|
||||
spread.symbol = symbol;
|
||||
return spread;
|
||||
}
|
||||
|
||||
function getNonReadonlySymbol(prop: Symbol) {
|
||||
@ -13914,7 +13920,7 @@ namespace ts {
|
||||
checkExternalEmitHelpers(memberDecl, ExternalEmitHelpers.Assign);
|
||||
}
|
||||
if (propertiesArray.length > 0) {
|
||||
spread = getSpreadType(spread, createObjectLiteralType());
|
||||
spread = getSpreadType(spread, createObjectLiteralType(), node.symbol, propagatedFlags);
|
||||
propertiesArray = [];
|
||||
propertiesTable = createSymbolTable();
|
||||
hasComputedStringProperty = false;
|
||||
@ -13926,7 +13932,7 @@ namespace ts {
|
||||
error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types);
|
||||
return unknownType;
|
||||
}
|
||||
spread = getSpreadType(spread, type);
|
||||
spread = getSpreadType(spread, type, node.symbol, propagatedFlags);
|
||||
offset = i + 1;
|
||||
continue;
|
||||
}
|
||||
@ -13971,14 +13977,7 @@ namespace ts {
|
||||
|
||||
if (spread !== emptyObjectType) {
|
||||
if (propertiesArray.length > 0) {
|
||||
spread = getSpreadType(spread, createObjectLiteralType());
|
||||
}
|
||||
if (spread.flags & TypeFlags.Object) {
|
||||
// only set the symbol and flags if this is a (fresh) object type
|
||||
spread.flags |= propagatedFlags;
|
||||
spread.flags |= TypeFlags.FreshLiteral;
|
||||
(spread as ObjectType).objectFlags |= ObjectFlags.ObjectLiteral;
|
||||
spread.symbol = node.symbol;
|
||||
spread = getSpreadType(spread, createObjectLiteralType(), node.symbol, propagatedFlags);
|
||||
}
|
||||
return spread;
|
||||
}
|
||||
@ -14099,7 +14098,7 @@ namespace ts {
|
||||
else {
|
||||
Debug.assert(attributeDecl.kind === SyntaxKind.JsxSpreadAttribute);
|
||||
if (attributesArray.length > 0) {
|
||||
spread = getSpreadType(spread, createJsxAttributesType(attributes.symbol, attributesTable));
|
||||
spread = getSpreadType(spread, createJsxAttributesType(attributes.symbol, attributesTable), openingLikeElement.symbol, /*propagatedFlags*/ 0);
|
||||
attributesArray = [];
|
||||
attributesTable = createSymbolTable();
|
||||
}
|
||||
@ -14108,7 +14107,7 @@ namespace ts {
|
||||
hasSpreadAnyType = true;
|
||||
}
|
||||
if (isValidSpreadType(exprType)) {
|
||||
spread = getSpreadType(spread, exprType);
|
||||
spread = getSpreadType(spread, exprType, openingLikeElement.symbol, /*propagatedFlags*/ 0);
|
||||
}
|
||||
else {
|
||||
typeToIntersect = typeToIntersect ? getIntersectionType([typeToIntersect, exprType]) : exprType;
|
||||
@ -14119,7 +14118,7 @@ namespace ts {
|
||||
if (!hasSpreadAnyType) {
|
||||
if (spread !== emptyObjectType) {
|
||||
if (attributesArray.length > 0) {
|
||||
spread = getSpreadType(spread, createJsxAttributesType(attributes.symbol, attributesTable));
|
||||
spread = getSpreadType(spread, createJsxAttributesType(attributes.symbol, attributesTable), openingLikeElement.symbol, /*propagatedFlags*/ 0);
|
||||
}
|
||||
attributesArray = getPropertiesOfType(spread);
|
||||
}
|
||||
|
||||
@ -0,0 +1,19 @@
|
||||
tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts(6,1): error TS7017: Element implicitly has an 'any' type because type '{ b: number; a: number; }' has no index signature.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts (1 errors) ====
|
||||
declare let indexed1: { [n: string]: number; a: number; };
|
||||
declare let indexed2: { [n: string]: boolean; c: boolean; };
|
||||
declare let indexed3: { [n: string]: number };
|
||||
let i = { ...indexed1, b: 11 };
|
||||
// only indexed has indexer, so i[101]: any
|
||||
i[101];
|
||||
~~~~~~
|
||||
!!! error TS7017: Element implicitly has an 'any' type because type '{ b: number; a: number; }' has no index signature.
|
||||
let ii = { ...indexed1, ...indexed2 };
|
||||
// both have indexer, so i[1001]: number | boolean
|
||||
ii[1001];
|
||||
|
||||
declare const b: boolean;
|
||||
indexed3 = { ...b ? indexed3 : undefined };
|
||||
|
||||
@ -1,23 +1,20 @@
|
||||
//// [objectSpreadIndexSignature.ts]
|
||||
interface Indexed {
|
||||
[n: string]: number;
|
||||
a: number;
|
||||
}
|
||||
interface Indexed2 {
|
||||
[n: string]: boolean;
|
||||
c: boolean;
|
||||
}
|
||||
let indexed: Indexed;
|
||||
let indexed2: Indexed2;
|
||||
let i = { ...indexed, b: 11 };
|
||||
declare let indexed1: { [n: string]: number; a: number; };
|
||||
declare let indexed2: { [n: string]: boolean; c: boolean; };
|
||||
declare let indexed3: { [n: string]: number };
|
||||
let i = { ...indexed1, b: 11 };
|
||||
// only indexed has indexer, so i[101]: any
|
||||
i[101];
|
||||
let ii = { ...indexed, ...indexed2 };
|
||||
let ii = { ...indexed1, ...indexed2 };
|
||||
// both have indexer, so i[1001]: number | boolean
|
||||
ii[1001];
|
||||
|
||||
declare const b: boolean;
|
||||
indexed3 = { ...b ? indexed3 : undefined };
|
||||
|
||||
|
||||
//// [objectSpreadIndexSignature.js]
|
||||
"use strict";
|
||||
var __assign = (this && this.__assign) || Object.assign || function(t) {
|
||||
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
||||
s = arguments[i];
|
||||
@ -26,11 +23,10 @@ var __assign = (this && this.__assign) || Object.assign || function(t) {
|
||||
}
|
||||
return t;
|
||||
};
|
||||
var indexed;
|
||||
var indexed2;
|
||||
var i = __assign({}, indexed, { b: 11 });
|
||||
var i = __assign({}, indexed1, { b: 11 });
|
||||
// only indexed has indexer, so i[101]: any
|
||||
i[101];
|
||||
var ii = __assign({}, indexed, indexed2);
|
||||
var ii = __assign({}, indexed1, indexed2);
|
||||
// both have indexer, so i[1001]: number | boolean
|
||||
ii[1001];
|
||||
indexed3 = __assign({}, b ? indexed3 : undefined);
|
||||
|
||||
@ -1,45 +1,42 @@
|
||||
=== tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts ===
|
||||
interface Indexed {
|
||||
>Indexed : Symbol(Indexed, Decl(objectSpreadIndexSignature.ts, 0, 0))
|
||||
declare let indexed1: { [n: string]: number; a: number; };
|
||||
>indexed1 : Symbol(indexed1, Decl(objectSpreadIndexSignature.ts, 0, 11))
|
||||
>n : Symbol(n, Decl(objectSpreadIndexSignature.ts, 0, 25))
|
||||
>a : Symbol(a, Decl(objectSpreadIndexSignature.ts, 0, 44))
|
||||
|
||||
[n: string]: number;
|
||||
>n : Symbol(n, Decl(objectSpreadIndexSignature.ts, 1, 5))
|
||||
declare let indexed2: { [n: string]: boolean; c: boolean; };
|
||||
>indexed2 : Symbol(indexed2, Decl(objectSpreadIndexSignature.ts, 1, 11))
|
||||
>n : Symbol(n, Decl(objectSpreadIndexSignature.ts, 1, 25))
|
||||
>c : Symbol(c, Decl(objectSpreadIndexSignature.ts, 1, 45))
|
||||
|
||||
a: number;
|
||||
>a : Symbol(Indexed.a, Decl(objectSpreadIndexSignature.ts, 1, 24))
|
||||
}
|
||||
interface Indexed2 {
|
||||
>Indexed2 : Symbol(Indexed2, Decl(objectSpreadIndexSignature.ts, 3, 1))
|
||||
declare let indexed3: { [n: string]: number };
|
||||
>indexed3 : Symbol(indexed3, Decl(objectSpreadIndexSignature.ts, 2, 11))
|
||||
>n : Symbol(n, Decl(objectSpreadIndexSignature.ts, 2, 25))
|
||||
|
||||
[n: string]: boolean;
|
||||
>n : Symbol(n, Decl(objectSpreadIndexSignature.ts, 5, 5))
|
||||
|
||||
c: boolean;
|
||||
>c : Symbol(Indexed2.c, Decl(objectSpreadIndexSignature.ts, 5, 25))
|
||||
}
|
||||
let indexed: Indexed;
|
||||
>indexed : Symbol(indexed, Decl(objectSpreadIndexSignature.ts, 8, 3))
|
||||
>Indexed : Symbol(Indexed, Decl(objectSpreadIndexSignature.ts, 0, 0))
|
||||
|
||||
let indexed2: Indexed2;
|
||||
>indexed2 : Symbol(indexed2, Decl(objectSpreadIndexSignature.ts, 9, 3))
|
||||
>Indexed2 : Symbol(Indexed2, Decl(objectSpreadIndexSignature.ts, 3, 1))
|
||||
|
||||
let i = { ...indexed, b: 11 };
|
||||
>i : Symbol(i, Decl(objectSpreadIndexSignature.ts, 10, 3))
|
||||
>indexed : Symbol(indexed, Decl(objectSpreadIndexSignature.ts, 8, 3))
|
||||
>b : Symbol(b, Decl(objectSpreadIndexSignature.ts, 10, 21))
|
||||
let i = { ...indexed1, b: 11 };
|
||||
>i : Symbol(i, Decl(objectSpreadIndexSignature.ts, 3, 3))
|
||||
>indexed1 : Symbol(indexed1, Decl(objectSpreadIndexSignature.ts, 0, 11))
|
||||
>b : Symbol(b, Decl(objectSpreadIndexSignature.ts, 3, 22))
|
||||
|
||||
// only indexed has indexer, so i[101]: any
|
||||
i[101];
|
||||
>i : Symbol(i, Decl(objectSpreadIndexSignature.ts, 10, 3))
|
||||
>i : Symbol(i, Decl(objectSpreadIndexSignature.ts, 3, 3))
|
||||
|
||||
let ii = { ...indexed, ...indexed2 };
|
||||
>ii : Symbol(ii, Decl(objectSpreadIndexSignature.ts, 13, 3))
|
||||
>indexed : Symbol(indexed, Decl(objectSpreadIndexSignature.ts, 8, 3))
|
||||
>indexed2 : Symbol(indexed2, Decl(objectSpreadIndexSignature.ts, 9, 3))
|
||||
let ii = { ...indexed1, ...indexed2 };
|
||||
>ii : Symbol(ii, Decl(objectSpreadIndexSignature.ts, 6, 3))
|
||||
>indexed1 : Symbol(indexed1, Decl(objectSpreadIndexSignature.ts, 0, 11))
|
||||
>indexed2 : Symbol(indexed2, Decl(objectSpreadIndexSignature.ts, 1, 11))
|
||||
|
||||
// both have indexer, so i[1001]: number | boolean
|
||||
ii[1001];
|
||||
>ii : Symbol(ii, Decl(objectSpreadIndexSignature.ts, 13, 3))
|
||||
>ii : Symbol(ii, Decl(objectSpreadIndexSignature.ts, 6, 3))
|
||||
|
||||
declare const b: boolean;
|
||||
>b : Symbol(b, Decl(objectSpreadIndexSignature.ts, 10, 13))
|
||||
|
||||
indexed3 = { ...b ? indexed3 : undefined };
|
||||
>indexed3 : Symbol(indexed3, Decl(objectSpreadIndexSignature.ts, 2, 11))
|
||||
>b : Symbol(b, Decl(objectSpreadIndexSignature.ts, 10, 13))
|
||||
>indexed3 : Symbol(indexed3, Decl(objectSpreadIndexSignature.ts, 2, 11))
|
||||
>undefined : Symbol(undefined)
|
||||
|
||||
|
||||
@ -1,34 +1,22 @@
|
||||
=== tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts ===
|
||||
interface Indexed {
|
||||
>Indexed : Indexed
|
||||
|
||||
[n: string]: number;
|
||||
declare let indexed1: { [n: string]: number; a: number; };
|
||||
>indexed1 : { [n: string]: number; a: number; }
|
||||
>n : string
|
||||
|
||||
a: number;
|
||||
>a : number
|
||||
}
|
||||
interface Indexed2 {
|
||||
>Indexed2 : Indexed2
|
||||
|
||||
[n: string]: boolean;
|
||||
declare let indexed2: { [n: string]: boolean; c: boolean; };
|
||||
>indexed2 : { [n: string]: boolean; c: boolean; }
|
||||
>n : string
|
||||
>c : boolean
|
||||
|
||||
declare let indexed3: { [n: string]: number };
|
||||
>indexed3 : { [n: string]: number; }
|
||||
>n : string
|
||||
|
||||
c: boolean;
|
||||
>c : boolean
|
||||
}
|
||||
let indexed: Indexed;
|
||||
>indexed : Indexed
|
||||
>Indexed : Indexed
|
||||
|
||||
let indexed2: Indexed2;
|
||||
>indexed2 : Indexed2
|
||||
>Indexed2 : Indexed2
|
||||
|
||||
let i = { ...indexed, b: 11 };
|
||||
let i = { ...indexed1, b: 11 };
|
||||
>i : { b: number; a: number; }
|
||||
>{ ...indexed, b: 11 } : { b: number; a: number; }
|
||||
>indexed : Indexed
|
||||
>{ ...indexed1, b: 11 } : { b: number; a: number; }
|
||||
>indexed1 : { [n: string]: number; a: number; }
|
||||
>b : number
|
||||
>11 : 11
|
||||
|
||||
@ -38,11 +26,11 @@ i[101];
|
||||
>i : { b: number; a: number; }
|
||||
>101 : 101
|
||||
|
||||
let ii = { ...indexed, ...indexed2 };
|
||||
let ii = { ...indexed1, ...indexed2 };
|
||||
>ii : { [x: string]: number | boolean; c: boolean; a: number; }
|
||||
>{ ...indexed, ...indexed2 } : { [x: string]: number | boolean; c: boolean; a: number; }
|
||||
>indexed : Indexed
|
||||
>indexed2 : Indexed2
|
||||
>{ ...indexed1, ...indexed2 } : { [x: string]: number | boolean; c: boolean; a: number; }
|
||||
>indexed1 : { [n: string]: number; a: number; }
|
||||
>indexed2 : { [n: string]: boolean; c: boolean; }
|
||||
|
||||
// both have indexer, so i[1001]: number | boolean
|
||||
ii[1001];
|
||||
@ -50,3 +38,15 @@ ii[1001];
|
||||
>ii : { [x: string]: number | boolean; c: boolean; a: number; }
|
||||
>1001 : 1001
|
||||
|
||||
declare const b: boolean;
|
||||
>b : boolean
|
||||
|
||||
indexed3 = { ...b ? indexed3 : undefined };
|
||||
>indexed3 = { ...b ? indexed3 : undefined } : {} | { [n: string]: number; }
|
||||
>indexed3 : { [n: string]: number; }
|
||||
>{ ...b ? indexed3 : undefined } : {} | { [n: string]: number; }
|
||||
>b ? indexed3 : undefined : { [n: string]: number; } | undefined
|
||||
>b : boolean
|
||||
>indexed3 : { [n: string]: number; }
|
||||
>undefined : undefined
|
||||
|
||||
|
||||
@ -1,16 +1,13 @@
|
||||
interface Indexed {
|
||||
[n: string]: number;
|
||||
a: number;
|
||||
}
|
||||
interface Indexed2 {
|
||||
[n: string]: boolean;
|
||||
c: boolean;
|
||||
}
|
||||
let indexed: Indexed;
|
||||
let indexed2: Indexed2;
|
||||
let i = { ...indexed, b: 11 };
|
||||
// @strict: true
|
||||
declare let indexed1: { [n: string]: number; a: number; };
|
||||
declare let indexed2: { [n: string]: boolean; c: boolean; };
|
||||
declare let indexed3: { [n: string]: number };
|
||||
let i = { ...indexed1, b: 11 };
|
||||
// only indexed has indexer, so i[101]: any
|
||||
i[101];
|
||||
let ii = { ...indexed, ...indexed2 };
|
||||
let ii = { ...indexed1, ...indexed2 };
|
||||
// both have indexer, so i[1001]: number | boolean
|
||||
ii[1001];
|
||||
|
||||
declare const b: boolean;
|
||||
indexed3 = { ...b ? indexed3 : undefined };
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user