Merge pull request #11150 from Microsoft/object-spread

Object spread/rest
This commit is contained in:
Nathan Shively-Sanders 2016-11-10 09:28:58 -08:00 committed by GitHub
commit be5e5fb872
96 changed files with 6520 additions and 1515 deletions

View File

@ -71,6 +71,7 @@ var compilerSources = [
"transformers/destructuring.ts",
"transformers/ts.ts",
"transformers/jsx.ts",
"transformers/esnext.ts",
"transformers/es2017.ts",
"transformers/es2016.ts",
"transformers/es2015.ts",
@ -107,6 +108,7 @@ var servicesSources = [
"transformers/destructuring.ts",
"transformers/ts.ts",
"transformers/jsx.ts",
"transformers/esnext.ts",
"transformers/es2017.ts",
"transformers/es2016.ts",
"transformers/es2015.ts",

View File

@ -1139,8 +1139,8 @@ namespace ts {
}
else if (node.kind === SyntaxKind.ArrayLiteralExpression) {
for (const e of (<ArrayLiteralExpression>node).elements) {
if (e.kind === SyntaxKind.SpreadElementExpression) {
bindAssignmentTargetFlow((<SpreadElementExpression>e).expression);
if (e.kind === SyntaxKind.SpreadElement) {
bindAssignmentTargetFlow((<SpreadElement>e).expression);
}
else {
bindDestructuringTargetFlow(e);
@ -1155,6 +1155,9 @@ namespace ts {
else if (p.kind === SyntaxKind.ShorthandPropertyAssignment) {
bindAssignmentTargetFlow((<ShorthandPropertyAssignment>p).name);
}
else if (p.kind === SyntaxKind.SpreadAssignment) {
bindAssignmentTargetFlow((<SpreadAssignment>p).expression);
}
}
}
}
@ -1916,6 +1919,9 @@ namespace ts {
return bindParameter(<ParameterDeclaration>node);
case SyntaxKind.VariableDeclaration:
case SyntaxKind.BindingElement:
if ((node as BindingElement).dotDotDotToken && node.parent.kind === SyntaxKind.ObjectBindingPattern) {
emitFlags |= NodeFlags.HasRestAttribute;
}
return bindVariableDeclarationOrBindingElement(<VariableDeclaration | BindingElement>node);
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
@ -1929,8 +1935,21 @@ namespace ts {
case SyntaxKind.EnumMember:
return bindPropertyOrMethodOrAccessor(<Declaration>node, SymbolFlags.EnumMember, SymbolFlags.EnumMemberExcludes);
case SyntaxKind.SpreadAssignment:
case SyntaxKind.JsxSpreadAttribute:
emitFlags |= NodeFlags.HasJsxSpreadAttributes;
let root = container;
let hasRest = false;
while (root.parent) {
if (root.kind === SyntaxKind.ObjectLiteralExpression &&
root.parent.kind === SyntaxKind.BinaryExpression &&
(root.parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken &&
(root.parent as BinaryExpression).left === root) {
hasRest = true;
break;
}
root = root.parent;
}
emitFlags |= hasRest ? NodeFlags.HasRestAttribute : NodeFlags.HasSpreadAttribute;
return;
case SyntaxKind.CallSignature:
@ -2495,9 +2514,9 @@ namespace ts {
transformFlags |= TransformFlags.AssertTypeScript;
}
if (subtreeFlags & TransformFlags.ContainsSpreadElementExpression
if (subtreeFlags & TransformFlags.ContainsSpreadExpression
|| isSuperOrSuperProperty(expression, expressionKind)) {
// If the this node contains a SpreadElementExpression, or is a super call, then it is an ES6
// If the this node contains a SpreadExpression, or is a super call, then it is an ES6
// node.
transformFlags |= TransformFlags.AssertES2015;
}
@ -2526,7 +2545,7 @@ namespace ts {
if (node.typeArguments) {
transformFlags |= TransformFlags.AssertTypeScript;
}
if (subtreeFlags & TransformFlags.ContainsSpreadElementExpression) {
if (subtreeFlags & TransformFlags.ContainsSpreadExpression) {
// If the this node contains a SpreadElementExpression then it is an ES6
// node.
transformFlags |= TransformFlags.AssertES2015;
@ -2541,10 +2560,13 @@ namespace ts {
const operatorTokenKind = node.operatorToken.kind;
const leftKind = node.left.kind;
if (operatorTokenKind === SyntaxKind.EqualsToken
&& (leftKind === SyntaxKind.ObjectLiteralExpression
|| leftKind === SyntaxKind.ArrayLiteralExpression)) {
// Destructuring assignments are ES6 syntax.
if (operatorTokenKind === SyntaxKind.EqualsToken && leftKind === SyntaxKind.ObjectLiteralExpression) {
// Destructuring object assignments with are ES2015 syntax
// and possibly ESNext if they contain rest
transformFlags |= TransformFlags.AssertESNext | TransformFlags.AssertES2015 | TransformFlags.AssertDestructuringAssignment;
}
else if (operatorTokenKind === SyntaxKind.EqualsToken && leftKind === SyntaxKind.ArrayLiteralExpression) {
// Destructuring assignments are ES2015 syntax.
transformFlags |= TransformFlags.AssertES2015 | TransformFlags.AssertDestructuringAssignment;
}
else if (operatorTokenKind === SyntaxKind.AsteriskAsteriskToken
@ -2578,6 +2600,11 @@ namespace ts {
transformFlags |= TransformFlags.AssertTypeScript | TransformFlags.ContainsParameterPropertyAssignments;
}
// parameters with object rest destructuring are ES Next syntax
if (subtreeFlags & TransformFlags.ContainsSpreadExpression) {
transformFlags |= TransformFlags.AssertESNext;
}
// If a parameter has an initializer, a binding pattern or a dotDotDot token, then
// it is ES6 syntax and its container must emit default value assignments or parameter destructuring downlevel.
if (subtreeFlags & TransformFlags.ContainsBindingPattern || initializer || dotDotDotToken) {
@ -2811,6 +2838,11 @@ namespace ts {
transformFlags |= TransformFlags.AssertES2017;
}
// function declarations with object rest destructuring are ES Next syntax
if (subtreeFlags & TransformFlags.ContainsSpreadExpression) {
transformFlags |= TransformFlags.AssertESNext;
}
// If a FunctionDeclaration's subtree has marked the container as needing to capture the
// lexical this, or the function contains parameters with initializers, then this node is
// ES6 syntax.
@ -2848,6 +2880,12 @@ namespace ts {
transformFlags |= TransformFlags.AssertES2017;
}
// function expressions with object rest destructuring are ES Next syntax
if (subtreeFlags & TransformFlags.ContainsSpreadExpression) {
transformFlags |= TransformFlags.AssertESNext;
}
// If a FunctionExpression's subtree has marked the container as needing to capture the
// lexical this, or the function contains parameters with initializers, then this node is
// ES6 syntax.
@ -2885,6 +2923,11 @@ namespace ts {
transformFlags |= TransformFlags.AssertES2017;
}
// arrow functions with object rest destructuring are ES Next syntax
if (subtreeFlags & TransformFlags.ContainsSpreadExpression) {
transformFlags |= TransformFlags.AssertESNext;
}
// If an ArrowFunction contains a lexical this, its container must capture the lexical this.
if (subtreeFlags & TransformFlags.ContainsLexicalThis) {
transformFlags |= TransformFlags.ContainsCapturedLexicalThis;
@ -2913,8 +2956,13 @@ namespace ts {
let transformFlags = subtreeFlags;
const nameKind = node.name.kind;
// A VariableDeclaration with a binding pattern is ES6 syntax.
if (nameKind === SyntaxKind.ObjectBindingPattern || nameKind === SyntaxKind.ArrayBindingPattern) {
// A VariableDeclaration with an object binding pattern is ES2015 syntax
// and possibly ESNext syntax if it contains an object binding pattern
if (nameKind === SyntaxKind.ObjectBindingPattern) {
transformFlags |= TransformFlags.AssertESNext | TransformFlags.AssertES2015 | TransformFlags.ContainsBindingPattern;
}
// A VariableDeclaration with an object binding pattern is ES2015 syntax.
else if (nameKind === SyntaxKind.ArrayBindingPattern) {
transformFlags |= TransformFlags.AssertES2015 | TransformFlags.ContainsBindingPattern;
}
@ -3055,6 +3103,10 @@ namespace ts {
transformFlags |= TransformFlags.AssertJsx;
break;
case SyntaxKind.ForOfStatement:
// for-of might be ESNext if it has a rest destructuring
transformFlags |= TransformFlags.AssertESNext;
// FALLTHROUGH
case SyntaxKind.NoSubstitutionTemplateLiteral:
case SyntaxKind.TemplateHead:
case SyntaxKind.TemplateMiddle:
@ -3062,7 +3114,6 @@ namespace ts {
case SyntaxKind.TemplateExpression:
case SyntaxKind.TaggedTemplateExpression:
case SyntaxKind.ShorthandPropertyAssignment:
case SyntaxKind.ForOfStatement:
case SyntaxKind.StaticKeyword:
// These nodes are ES6 syntax.
transformFlags |= TransformFlags.AssertES2015;
@ -3126,11 +3177,18 @@ namespace ts {
}
break;
case SyntaxKind.SpreadElementExpression:
// This node is ES6 syntax, but is handled by a containing node.
transformFlags |= TransformFlags.ContainsSpreadElementExpression;
case SyntaxKind.SpreadElement:
case SyntaxKind.SpreadAssignment:
// This node is ES6 or ES next syntax, but is handled by a containing node.
transformFlags |= TransformFlags.ContainsSpreadExpression;
break;
case SyntaxKind.BindingElement:
if ((node as BindingElement).dotDotDotToken) {
// this node is ES2015 or ES next syntax, but is handled by a containing node.
transformFlags |= TransformFlags.ContainsSpreadExpression;
}
case SyntaxKind.SuperKeyword:
// This node is ES6 syntax.
transformFlags |= TransformFlags.AssertES2015;
@ -3143,8 +3201,13 @@ namespace ts {
case SyntaxKind.ObjectBindingPattern:
case SyntaxKind.ArrayBindingPattern:
// These nodes are ES6 syntax.
transformFlags |= TransformFlags.AssertES2015 | TransformFlags.ContainsBindingPattern;
// These nodes are ES2015 or ES Next syntax.
if (subtreeFlags & TransformFlags.ContainsSpreadExpression) {
transformFlags |= TransformFlags.AssertESNext | TransformFlags.ContainsBindingPattern;
}
else {
transformFlags |= TransformFlags.AssertES2015 | TransformFlags.ContainsBindingPattern;
}
break;
case SyntaxKind.Decorator:
@ -3166,13 +3229,19 @@ namespace ts {
transformFlags |= TransformFlags.ContainsLexicalThis;
}
if (subtreeFlags & TransformFlags.ContainsSpreadExpression) {
// If an ObjectLiteralExpression contains a spread element, then it
// is an ES next node.
transformFlags |= TransformFlags.AssertESNext;
}
break;
case SyntaxKind.ArrayLiteralExpression:
case SyntaxKind.NewExpression:
excludeFlags = TransformFlags.ArrayLiteralOrCallOrNewExcludes;
if (subtreeFlags & TransformFlags.ContainsSpreadElementExpression) {
// If the this node contains a SpreadElementExpression, then it is an ES6
if (subtreeFlags & TransformFlags.ContainsSpreadExpression) {
// If the this node contains a SpreadExpression, then it is an ES6
// node.
transformFlags |= TransformFlags.AssertES2015;
}

View File

@ -2494,6 +2494,13 @@ namespace ts {
writePunctuation(writer, SyntaxKind.OpenBraceToken);
writer.writeLine();
writer.increaseIndent();
writeObjectLiteralType(resolved);
writer.decreaseIndent();
writePunctuation(writer, SyntaxKind.CloseBraceToken);
inObjectTypeLiteral = saveInObjectTypeLiteral;
}
function writeObjectLiteralType(resolved: ResolvedType) {
for (const signature of resolved.callSignatures) {
buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, /*kind*/ undefined, symbolStack);
writePunctuation(writer, SyntaxKind.SemicolonToken);
@ -2526,11 +2533,8 @@ namespace ts {
writer.writeLine();
}
}
writer.decreaseIndent();
writePunctuation(writer, SyntaxKind.CloseBraceToken);
inObjectTypeLiteral = saveInObjectTypeLiteral;
}
}
}
function buildTypeParameterDisplayFromSymbol(symbol: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags) {
const targetSymbol = getTargetSymbol(symbol);
@ -2972,26 +2976,31 @@ namespace ts {
return symbol && getSymbolLinks(symbol).type || getTypeForVariableLikeDeclaration(node, /*includeOptionality*/ false);
}
function getTextOfPropertyName(name: PropertyName): string {
switch (name.kind) {
case SyntaxKind.Identifier:
return (<Identifier>name).text;
case SyntaxKind.StringLiteral:
case SyntaxKind.NumericLiteral:
return (<LiteralExpression>name).text;
case SyntaxKind.ComputedPropertyName:
if (isStringOrNumericLiteral((<ComputedPropertyName>name).expression.kind)) {
return (<LiteralExpression>(<ComputedPropertyName>name).expression).text;
}
}
return undefined;
}
function isComputedNonLiteralName(name: PropertyName): boolean {
return name.kind === SyntaxKind.ComputedPropertyName && !isStringOrNumericLiteral((<ComputedPropertyName>name).expression.kind);
}
function getRestType(source: Type, properties: PropertyName[], symbol: Symbol): Type {
Debug.assert(!!(source.flags & TypeFlags.Object), "Rest types only support object types right now.");
const members = createMap<Symbol>();
const names = createMap<true>();
for (const name of properties) {
names[getTextOfPropertyName(name)] = true;
}
for (const prop of getPropertiesOfType(source)) {
const inNamesToRemove = prop.name in names;
const isPrivate = getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected);
const isMethod = prop.flags & SymbolFlags.Method;
const isSetOnlyAccessor = prop.flags & SymbolFlags.SetAccessor && !(prop.flags & SymbolFlags.GetAccessor);
if (!inNamesToRemove && !isPrivate && !isMethod && !isSetOnlyAccessor) {
members[prop.name] = prop;
}
}
const stringIndexInfo = getIndexInfoOfType(source, IndexKind.String);
const numberIndexInfo = getIndexInfoOfType(source, IndexKind.Number);
return createAnonymousType(symbol, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
}
/** Return the inferred type for a binding element */
function getTypeForBindingElement(declaration: BindingElement): Type {
const pattern = <BindingPattern>declaration.parent;
@ -3012,26 +3021,41 @@ namespace ts {
let type: Type;
if (pattern.kind === SyntaxKind.ObjectBindingPattern) {
// Use explicitly specified property name ({ p: xxx } form), or otherwise the implied name ({ p } form)
const name = declaration.propertyName || <Identifier>declaration.name;
if (isComputedNonLiteralName(name)) {
// computed properties with non-literal names are treated as 'any'
return anyType;
}
if (declaration.initializer) {
getContextualType(declaration.initializer);
if (declaration.dotDotDotToken) {
if (!(parentType.flags & TypeFlags.Object)) {
error(declaration, Diagnostics.Rest_types_may_only_be_created_from_object_types);
return unknownType;
}
const literalMembers: PropertyName[] = [];
for (const element of pattern.elements) {
if (element.kind !== SyntaxKind.OmittedExpression && !(element as BindingElement).dotDotDotToken) {
literalMembers.push(element.propertyName || element.name as Identifier);
}
}
type = getRestType(parentType, literalMembers, declaration.symbol);
}
else {
// Use explicitly specified property name ({ p: xxx } form), or otherwise the implied name ({ p } form)
const name = declaration.propertyName || <Identifier>declaration.name;
if (isComputedNonLiteralName(name)) {
// computed properties with non-literal names are treated as 'any'
return anyType;
}
if (declaration.initializer) {
getContextualType(declaration.initializer);
}
// Use type of the specified property, or otherwise, for a numeric name, the type of the numeric index signature,
// or otherwise the type of the string index signature.
const text = getTextOfPropertyName(name);
// Use type of the specified property, or otherwise, for a numeric name, the type of the numeric index signature,
// or otherwise the type of the string index signature.
const text = getTextOfPropertyName(name);
type = getTypeOfPropertyOfType(parentType, text) ||
isNumericLiteralName(text) && getIndexTypeOfType(parentType, IndexKind.Number) ||
getIndexTypeOfType(parentType, IndexKind.String);
if (!type) {
error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(parentType), declarationNameToString(name));
return unknownType;
type = getTypeOfPropertyOfType(parentType, text) ||
isNumericLiteralName(text) && getIndexTypeOfType(parentType, IndexKind.Number) ||
getIndexTypeOfType(parentType, IndexKind.String);
if (!type) {
error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(parentType), declarationNameToString(name));
return unknownType;
}
}
}
else {
@ -3039,7 +3063,11 @@ namespace ts {
// present (aka the tuple element property). This call also checks that the parentType is in
// fact an iterable or array (depending on target language).
const elementType = checkIteratedTypeOrElementType(parentType, pattern, /*allowStringInput*/ false);
if (!declaration.dotDotDotToken) {
if (declaration.dotDotDotToken) {
// Rest element has an array type with the same element type as the parent type
type = createArrayType(elementType);
}
else {
// Use specific property type when parent is a tuple or numeric index type when parent is an array
const propName = "" + indexOf(pattern.elements, declaration);
type = isTupleLikeType(parentType)
@ -3055,10 +3083,6 @@ namespace ts {
return unknownType;
}
}
else {
// Rest element has an array type with the same element type as the parent type
type = createArrayType(elementType);
}
}
// In strict null checking mode, if a default value of a non-undefined type is specified, remove
// undefined from the final type.
@ -3239,8 +3263,8 @@ namespace ts {
let hasComputedProperties = false;
forEach(pattern.elements, e => {
const name = e.propertyName || <Identifier>e.name;
if (isComputedNonLiteralName(name)) {
// do not include computed properties in the implied type
if (isComputedNonLiteralName(name) || e.dotDotDotToken) {
// do not include computed properties or rests in the implied type
hasComputedProperties = true;
return;
}
@ -4337,6 +4361,11 @@ namespace ts {
getIntersectionType([info1.type, info2.type]), info1.isReadonly && info2.isReadonly);
}
function unionSpreadIndexInfos(info1: IndexInfo, info2: IndexInfo): IndexInfo {
return info1 && info2 && createIndexInfo(
getUnionType([info1.type, info2.type]), info1.isReadonly || info2.isReadonly);
}
function resolveIntersectionTypeMembers(type: IntersectionType) {
// The members and properties collections are empty for intersection types. To get all properties of an
// intersection type use getPropertiesOfType (only the language service uses this).
@ -4473,7 +4502,9 @@ namespace ts {
function getPropertiesOfType(type: Type): Symbol[] {
type = getApparentType(type);
return type.flags & TypeFlags.UnionOrIntersection ? getPropertiesOfUnionOrIntersectionType(<UnionType>type) : getPropertiesOfObjectType(type);
return type.flags & TypeFlags.UnionOrIntersection ?
getPropertiesOfUnionOrIntersectionType(<UnionType>type) :
getPropertiesOfObjectType(type);
}
/**
@ -4528,6 +4559,7 @@ namespace ts {
if (isReadonlySymbol(prop)) {
isReadonly = true;
}
}
else if (containingType.flags & TypeFlags.Union) {
isPartial = true;
@ -5860,6 +5892,68 @@ namespace ts {
return links.resolvedType;
}
/**
* Since the source of spread types are object literals, which are not binary,
* 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, isFromObjectLiteral: boolean): ResolvedType | IntrinsicType {
Debug.assert(!!(left.flags & (TypeFlags.Object | TypeFlags.Any)) && !!(right.flags & (TypeFlags.Object | TypeFlags.Any)), "Only object types may be spread.");
if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) {
return anyType;
}
const members = createMap<Symbol>();
const skippedPrivateMembers = createMap<boolean>();
let stringIndexInfo: IndexInfo;
let numberIndexInfo: IndexInfo;
if (left === emptyObjectType) {
// for the first spread element, left === emptyObjectType, so take the right's string indexer
stringIndexInfo = getIndexInfoOfType(right, IndexKind.String);
numberIndexInfo = getIndexInfoOfType(right, IndexKind.Number);
}
else {
stringIndexInfo = unionSpreadIndexInfos(getIndexInfoOfType(left, IndexKind.String), getIndexInfoOfType(right, IndexKind.String));
numberIndexInfo = unionSpreadIndexInfos(getIndexInfoOfType(left, IndexKind.Number), getIndexInfoOfType(right, IndexKind.Number));
}
for (const rightProp of getPropertiesOfType(right)) {
// we approximate own properties as non-methods plus methods that are inside the object literal
const isOwnProperty = !(rightProp.flags & SymbolFlags.Method) || isFromObjectLiteral;
const isSetterWithoutGetter = rightProp.flags & SymbolFlags.SetAccessor && !(rightProp.flags & SymbolFlags.GetAccessor);
if (getDeclarationModifierFlagsFromSymbol(rightProp) & (ModifierFlags.Private | ModifierFlags.Protected)) {
skippedPrivateMembers[rightProp.name] = true;
}
else if (isOwnProperty && !isSetterWithoutGetter) {
members[rightProp.name] = rightProp;
}
}
for (const leftProp of getPropertiesOfType(left)) {
if (leftProp.flags & SymbolFlags.SetAccessor && !(leftProp.flags & SymbolFlags.GetAccessor)
|| leftProp.name in skippedPrivateMembers) {
continue;
}
if (leftProp.name in members) {
const rightProp = members[leftProp.name];
const rightType = getTypeOfSymbol(rightProp);
if (maybeTypeOfKind(rightType, TypeFlags.Undefined) || rightProp.flags & SymbolFlags.Optional) {
const declarations: Declaration[] = concatenate(leftProp.declarations, rightProp.declarations);
const flags = SymbolFlags.Property | SymbolFlags.Transient | (leftProp.flags & SymbolFlags.Optional);
const result = <TransientSymbol>createSymbol(flags, leftProp.name);
result.type = getUnionType([getTypeOfSymbol(leftProp), getTypeWithFacts(rightType, TypeFacts.NEUndefined)]);
result.leftSpread = leftProp;
result.rightSpread = rightProp;
result.declarations = declarations;
result.isReadonly = isReadonlySymbol(leftProp) || isReadonlySymbol(rightProp);
members[leftProp.name] = result;
}
}
else {
members[leftProp.name] = leftProp;
}
}
return createAnonymousType(undefined, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
}
function createLiteralType(flags: TypeFlags, text: string) {
const type = <LiteralType>createType(flags);
type.text = text;
@ -8571,7 +8665,7 @@ namespace ts {
unknownType;
}
function getTypeOfDestructuredSpreadElement(type: Type) {
function getTypeOfDestructuredSpreadExpression(type: Type) {
return createArrayType(checkIteratedTypeOrElementType(type, /*errorNode*/ undefined, /*allowStringInput*/ false) || unknownType);
}
@ -8585,8 +8679,8 @@ namespace ts {
return getTypeOfDestructuredArrayElement(getAssignedType(node), indexOf(node.elements, element));
}
function getAssignedTypeOfSpreadElement(node: SpreadElementExpression): Type {
return getTypeOfDestructuredSpreadElement(getAssignedType(<ArrayLiteralExpression>node.parent));
function getAssignedTypeOfSpreadExpression(node: SpreadElement): Type {
return getTypeOfDestructuredSpreadExpression(getAssignedType(<ArrayLiteralExpression>node.parent));
}
function getAssignedTypeOfPropertyAssignment(node: PropertyAssignment | ShorthandPropertyAssignment): Type {
@ -8610,8 +8704,8 @@ namespace ts {
return undefinedType;
case SyntaxKind.ArrayLiteralExpression:
return getAssignedTypeOfArrayLiteralElement(<ArrayLiteralExpression>parent, node);
case SyntaxKind.SpreadElementExpression:
return getAssignedTypeOfSpreadElement(<SpreadElementExpression>parent);
case SyntaxKind.SpreadElement:
return getAssignedTypeOfSpreadExpression(<SpreadElement>parent);
case SyntaxKind.PropertyAssignment:
return getAssignedTypeOfPropertyAssignment(<PropertyAssignment>parent);
case SyntaxKind.ShorthandPropertyAssignment:
@ -8627,7 +8721,7 @@ namespace ts {
getTypeOfDestructuredProperty(parentType, node.propertyName || <Identifier>node.name) :
!node.dotDotDotToken ?
getTypeOfDestructuredArrayElement(parentType, indexOf(pattern.elements, node)) :
getTypeOfDestructuredSpreadElement(parentType);
getTypeOfDestructuredSpreadExpression(parentType);
return getTypeWithDefault(type, node.initializer);
}
@ -10642,7 +10736,7 @@ namespace ts {
return mapper && mapper.context;
}
function checkSpreadElementExpression(node: SpreadElementExpression, contextualMapper?: TypeMapper): Type {
function checkSpreadExpression(node: SpreadElement, contextualMapper?: TypeMapper): Type {
// It is usually not safe to call checkExpressionCached if we can be contextually typing.
// You can tell that we are contextually typing because of the contextualMapper parameter.
// While it is true that a spread element can have a contextual type, it does not do anything
@ -10664,7 +10758,7 @@ namespace ts {
const elementTypes: Type[] = [];
const inDestructuringPattern = isAssignmentTarget(node);
for (const e of elements) {
if (inDestructuringPattern && e.kind === SyntaxKind.SpreadElementExpression) {
if (inDestructuringPattern && e.kind === SyntaxKind.SpreadElement) {
// Given the following situation:
// var c: {};
// [...c] = ["", 0];
@ -10677,7 +10771,7 @@ namespace ts {
// get the contextual element type from it. So we do something similar to
// getContextualTypeForElementExpression, which will crucially not error
// if there is no index type / iterated type.
const restArrayType = checkExpression((<SpreadElementExpression>e).expression, contextualMapper);
const restArrayType = checkExpression((<SpreadElement>e).expression, contextualMapper);
const restElementType = getIndexTypeOfType(restArrayType, IndexKind.Number) ||
(languageVersion >= ScriptTarget.ES2015 ? getElementTypeOfIterable(restArrayType, /*errorNode*/ undefined) : undefined);
if (restElementType) {
@ -10688,7 +10782,7 @@ namespace ts {
const type = checkExpressionForMutableLocation(e, contextualMapper);
elementTypes.push(type);
}
hasSpreadElement = hasSpreadElement || e.kind === SyntaxKind.SpreadElementExpression;
hasSpreadElement = hasSpreadElement || e.kind === SyntaxKind.SpreadElement;
}
if (!hasSpreadElement) {
// If array literal is actually a destructuring pattern, mark it as an implied type. We do this such
@ -10805,8 +10899,11 @@ namespace ts {
// Grammar checking
checkGrammarObjectLiteralExpression(node, inDestructuringPattern);
const propertiesTable = createMap<Symbol>();
const propertiesArray: Symbol[] = [];
let propertiesTable = createMap<Symbol>();
let propertiesArray: Symbol[] = [];
let spread: Type = emptyObjectType;
let propagatedFlags: TypeFlags = 0;
const contextualType = getApparentTypeOfContextualType(node);
const contextualTypeHasPattern = contextualType && contextualType.pattern &&
(contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression);
@ -10831,6 +10928,7 @@ namespace ts {
Debug.assert(memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment);
type = checkExpressionForMutableLocation((<ShorthandPropertyAssignment>memberDecl).name, contextualMapper);
}
typeFlags |= type.flags;
const prop = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient | member.flags, member.name);
if (inDestructuringPattern) {
@ -10868,6 +10966,23 @@ namespace ts {
prop.target = member;
member = prop;
}
else if (memberDecl.kind === SyntaxKind.SpreadAssignment) {
if (propertiesArray.length > 0) {
spread = getSpreadType(spread, createObjectLiteralType(), /*isFromObjectLiteral*/ true);
propertiesArray = [];
propertiesTable = createMap<Symbol>();
hasComputedStringProperty = false;
hasComputedNumberProperty = false;
typeFlags = 0;
}
const type = checkExpression((memberDecl as SpreadAssignment).expression);
if (!(type.flags & (TypeFlags.Object | TypeFlags.Any))) {
error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types);
return unknownType;
}
spread = getSpreadType(spread, type, /*isFromObjectLiteral*/ false);
continue;
}
else {
// TypeScript 1.0 spec (April 2014)
// A get accessor declaration is processed in the same manner as
@ -10907,20 +11022,36 @@ namespace ts {
}
}
const stringIndexInfo = hasComputedStringProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.String) : undefined;
const numberIndexInfo = hasComputedNumberProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.Number) : undefined;
const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshLiteral;
result.flags |= TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags);
result.objectFlags |= ObjectFlags.ObjectLiteral;
if (patternWithComputedProperties) {
result.objectFlags |= ObjectFlags.ObjectLiteralPatternWithComputedProperties;
if (spread !== emptyObjectType) {
if (propertiesArray.length > 0) {
spread = getSpreadType(spread, createObjectLiteralType(), /*isFromObjectLiteral*/ true);
}
spread.flags |= propagatedFlags;
spread.symbol = node.symbol;
return spread;
}
if (inDestructuringPattern) {
result.pattern = node;
return createObjectLiteralType();
function createObjectLiteralType() {
const stringIndexInfo = hasComputedStringProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.String) : undefined;
const numberIndexInfo = hasComputedNumberProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.Number) : undefined;
const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshLiteral;
result.flags |= TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags);
result.objectFlags |= ObjectFlags.ObjectLiteral;
if (patternWithComputedProperties) {
result.objectFlags |= ObjectFlags.ObjectLiteralPatternWithComputedProperties;
}
if (inDestructuringPattern) {
result.pattern = node;
}
if (!(result.flags & TypeFlags.Nullable)) {
propagatedFlags |= (result.flags & TypeFlags.PropagatingFlags);
}
return result;
}
return result;
}
}
function checkJsxSelfClosingElement(node: JsxSelfClosingElement) {
checkJsxOpeningLikeElement(node);
@ -11819,7 +11950,7 @@ namespace ts {
function getSpreadArgumentIndex(args: Expression[]): number {
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (arg && arg.kind === SyntaxKind.SpreadElementExpression) {
if (arg && arg.kind === SyntaxKind.SpreadElement) {
return i;
}
}
@ -13785,7 +13916,7 @@ namespace ts {
error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(objectLiteralType), declarationNameToString(name));
}
}
else {
else if (property.kind !== SyntaxKind.SpreadAssignment) {
error(property, Diagnostics.Property_assignment_expected);
}
}
@ -13807,7 +13938,7 @@ namespace ts {
const elements = node.elements;
const element = elements[elementIndex];
if (element.kind !== SyntaxKind.OmittedExpression) {
if (element.kind !== SyntaxKind.SpreadElementExpression) {
if (element.kind !== SyntaxKind.SpreadElement) {
const propName = "" + elementIndex;
const type = isTypeAny(sourceType)
? sourceType
@ -13831,10 +13962,10 @@ namespace ts {
}
else {
if (elementIndex < elements.length - 1) {
error(element, Diagnostics.A_rest_element_must_be_last_in_an_array_destructuring_pattern);
error(element, Diagnostics.A_rest_element_must_be_last_in_a_destructuring_pattern);
}
else {
const restExpression = (<SpreadElementExpression>element).expression;
const restExpression = (<SpreadElement>element).expression;
if (restExpression.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>restExpression).operatorToken.kind === SyntaxKind.EqualsToken) {
error((<BinaryExpression>restExpression).operatorToken, Diagnostics.A_rest_element_cannot_have_an_initializer);
}
@ -14467,8 +14598,8 @@ namespace ts {
return checkBinaryExpression(<BinaryExpression>node, contextualMapper);
case SyntaxKind.ConditionalExpression:
return checkConditionalExpression(<ConditionalExpression>node, contextualMapper);
case SyntaxKind.SpreadElementExpression:
return checkSpreadElementExpression(<SpreadElementExpression>node, contextualMapper);
case SyntaxKind.SpreadElement:
return checkSpreadExpression(<SpreadElement>node, contextualMapper);
case SyntaxKind.OmittedExpression:
return undefinedWideningType;
case SyntaxKind.YieldExpression:
@ -19115,6 +19246,10 @@ namespace ts {
return symbols;
}
else if (symbol.flags & SymbolFlags.Transient) {
if ((symbol as SymbolLinks).leftSpread) {
const links = symbol as SymbolLinks;
return [links.leftSpread, links.rightSpread];
}
let target: Symbol;
let next = symbol;
while (next = getSymbolLinks(next).target) {
@ -19815,7 +19950,7 @@ namespace ts {
if (requestedExternalEmitHelpers & NodeFlags.HasClassExtends && languageVersion < ScriptTarget.ES2015) {
verifyHelperSymbol(exports, "__extends", SymbolFlags.Value);
}
if (requestedExternalEmitHelpers & NodeFlags.HasJsxSpreadAttributes && compilerOptions.jsx !== JsxEmit.Preserve) {
if (requestedExternalEmitHelpers & NodeFlags.HasSpreadAttribute && compilerOptions.jsx !== JsxEmit.Preserve) {
verifyHelperSymbol(exports, "__assign", SymbolFlags.Value);
}
if (requestedExternalEmitHelpers & NodeFlags.HasDecorators) {
@ -20378,7 +20513,6 @@ namespace ts {
checkGrammarHeritageClause(heritageClause);
}
}
return false;
}
@ -20426,6 +20560,9 @@ namespace ts {
const GetOrSetAccessor = GetAccessor | SetAccessor;
for (const prop of node.properties) {
if (prop.kind === SyntaxKind.SpreadAssignment) {
continue;
}
const name = prop.name;
if (name.kind === SyntaxKind.ComputedPropertyName) {
// If the name is not a ComputedPropertyName, the grammar checking will skip it
@ -20729,7 +20866,7 @@ namespace ts {
if (node.dotDotDotToken) {
const elements = (<BindingPattern>node.parent).elements;
if (node !== lastOrUndefined(elements)) {
return grammarErrorOnNode(node, Diagnostics.A_rest_element_must_be_last_in_an_array_destructuring_pattern);
return grammarErrorOnNode(node, Diagnostics.A_rest_element_must_be_last_in_a_destructuring_pattern);
}
if (node.name.kind === SyntaxKind.ArrayBindingPattern || node.name.kind === SyntaxKind.ObjectBindingPattern) {
@ -20737,7 +20874,7 @@ namespace ts {
}
if (node.initializer) {
// Error on equals token which immediate precedes the initializer
// Error on equals token which immediately precedes the initializer
return grammarErrorAtPos(getSourceFileOfNode(node), node.initializer.pos - 1, 1, Diagnostics.A_rest_element_cannot_have_an_initializer);
}
}

View File

@ -265,6 +265,7 @@ namespace ts {
"es2015": ScriptTarget.ES2015,
"es2016": ScriptTarget.ES2016,
"es2017": ScriptTarget.ES2017,
"esnext": ScriptTarget.ESNext,
}),
description: Diagnostics.Specify_ECMAScript_target_version_Colon_ES3_default_ES5_or_ES2015,
paramType: Diagnostics.VERSION,

View File

@ -1455,7 +1455,7 @@
"category": "Error",
"code": 2461
},
"A rest element must be last in an array destructuring pattern": {
"A rest element must be last in a destructuring pattern": {
"category": "Error",
"code": 2462
},
@ -1983,6 +1983,14 @@
"category": "Error",
"code": 2697
},
"Spread types may only be created from object types.": {
"category": "Error",
"code": 2698
},
"Rest types may only be created from object types.": {
"category": "Error",
"code": 2700
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",

View File

@ -42,6 +42,14 @@ var __assign = (this && this.__assign) || Object.assign || function(t) {
return t;
};`;
const restHelper = `
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && !e.indexOf(p))
t[p] = s[p];
return t;
};`;
// emit output for the __decorate helper function
const decorateHelper = `
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
@ -226,6 +234,7 @@ const _super = (function (geti, seti) {
let currentFileIdentifiers: Map<string>;
let extendsEmitted: boolean;
let assignEmitted: boolean;
let restEmitted: boolean;
let decorateEmitted: boolean;
let paramEmitted: boolean;
let awaiterEmitted: boolean;
@ -732,6 +741,8 @@ const _super = (function (geti, seti) {
return emitPropertyAssignment(<PropertyAssignment>node);
case SyntaxKind.ShorthandPropertyAssignment:
return emitShorthandPropertyAssignment(<ShorthandPropertyAssignment>node);
case SyntaxKind.SpreadAssignment:
return emitSpreadAssignment(node as SpreadAssignment);
// Enum
case SyntaxKind.EnumMember:
@ -822,8 +833,8 @@ const _super = (function (geti, seti) {
return emitTemplateExpression(<TemplateExpression>node);
case SyntaxKind.YieldExpression:
return emitYieldExpression(<YieldExpression>node);
case SyntaxKind.SpreadElementExpression:
return emitSpreadElementExpression(<SpreadElementExpression>node);
case SyntaxKind.SpreadElement:
return emitSpreadExpression(<SpreadElement>node);
case SyntaxKind.ClassExpression:
return emitClassExpression(<ClassExpression>node);
case SyntaxKind.OmittedExpression:
@ -1374,7 +1385,7 @@ const _super = (function (geti, seti) {
emitExpressionWithPrefix(" ", node.expression);
}
function emitSpreadElementExpression(node: SpreadElementExpression) {
function emitSpreadExpression(node: SpreadElement) {
write("...");
emitExpression(node.expression);
}
@ -2102,6 +2113,13 @@ const _super = (function (geti, seti) {
}
}
function emitSpreadAssignment(node: SpreadAssignment) {
if (node.expression) {
write("...");
emitExpression(node.expression);
}
}
//
// Enum
//
@ -2205,11 +2223,19 @@ const _super = (function (geti, seti) {
helpersEmitted = true;
}
if (compilerOptions.jsx !== JsxEmit.Preserve && !assignEmitted && (node.flags & NodeFlags.HasJsxSpreadAttributes)) {
if ((languageVersion < ScriptTarget.ESNext || currentSourceFile.scriptKind === ScriptKind.JSX || currentSourceFile.scriptKind === ScriptKind.TSX) &&
compilerOptions.jsx !== JsxEmit.Preserve &&
!assignEmitted &&
node.flags & NodeFlags.HasSpreadAttribute) {
writeLines(assignHelper);
assignEmitted = true;
}
if (languageVersion < ScriptTarget.ESNext && !restEmitted && node.flags & NodeFlags.HasRestAttribute) {
writeLines(restHelper);
restEmitted = true;
}
if (!decorateEmitted && node.flags & NodeFlags.HasDecorators) {
writeLines(decorateHelper);
if (compilerOptions.emitDecoratorMetadata) {

View File

@ -692,12 +692,12 @@ namespace ts {
}
export function createSpread(expression: Expression, location?: TextRange) {
const node = <SpreadElementExpression>createNode(SyntaxKind.SpreadElementExpression, location);
const node = <SpreadElement>createNode(SyntaxKind.SpreadElement, location);
node.expression = parenthesizeExpressionForList(expression);
return node;
}
export function updateSpread(node: SpreadElementExpression, expression: Expression) {
export function updateSpread(node: SpreadElement, expression: Expression) {
if (node.expression !== expression) {
return updateNode(createSpread(expression, node), node);
}
@ -1399,14 +1399,27 @@ namespace ts {
return node;
}
export function updateShorthandPropertyAssignment(node: ShorthandPropertyAssignment, name: Identifier, objectAssignmentInitializer: Expression) {
export function createSpreadAssignment(expression: Expression, location?: TextRange) {
const node = <SpreadAssignment>createNode(SyntaxKind.SpreadAssignment, location);
node.expression = expression !== undefined ? parenthesizeExpressionForList(expression) : undefined;
return node;
}
export function updateShorthandPropertyAssignment(node: ShorthandPropertyAssignment, name: Identifier, objectAssignmentInitializer: Expression) {
if (node.name !== name || node.objectAssignmentInitializer !== objectAssignmentInitializer) {
return updateNode(createShorthandPropertyAssignment(name, objectAssignmentInitializer, node), node);
}
return node;
}
// Top-level nodes
export function updateSpreadAssignment(node: SpreadAssignment, expression: Expression) {
if (node.expression !== expression) {
return updateNode(createSpreadAssignment(expression, node), node);
}
return node;
}
// Top-level nodes
export function updateSourceFileNode(node: SourceFile, statements: Statement[]) {
if (node.statements !== statements) {
@ -3055,4 +3068,538 @@ namespace ts {
function tryGetModuleNameFromDeclaration(declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration, host: EmitHost, resolver: EmitResolver, compilerOptions: CompilerOptions) {
return tryGetModuleNameFromFile(resolver.getExternalModuleFileFromDeclaration(declaration), host, compilerOptions);
}
/**
* Transforms the body of a function-like node.
*
* @param node A function-like node.
*/
export function transformFunctionBody(node: FunctionLikeDeclaration,
visitor: (node: Node) => VisitResult<Node>,
currentSourceFile: SourceFile,
context: TransformationContext,
enableSubstitutionsForCapturedThis: () => void,
convertObjectRest?: boolean) {
let multiLine = false; // indicates whether the block *must* be emitted as multiple lines
let singleLine = false; // indicates whether the block *may* be emitted as a single line
let statementsLocation: TextRange;
let closeBraceLocation: TextRange;
const statements: Statement[] = [];
const body = node.body;
let statementOffset: number;
context.startLexicalEnvironment();
if (isBlock(body)) {
// ensureUseStrict is false because no new prologue-directive should be added.
// addPrologueDirectives will simply put already-existing directives at the beginning of the target statement-array
statementOffset = addPrologueDirectives(statements, body.statements, /*ensureUseStrict*/ false, visitor);
}
addCaptureThisForNodeIfNeeded(statements, node, enableSubstitutionsForCapturedThis);
addDefaultValueAssignmentsIfNeeded(statements, node, visitor, convertObjectRest);
addRestParameterIfNeeded(statements, node, /*inConstructorWithSynthesizedSuper*/ false);
// If we added any generated statements, this must be a multi-line block.
if (!multiLine && statements.length > 0) {
multiLine = true;
}
if (isBlock(body)) {
statementsLocation = body.statements;
addRange(statements, visitNodes(body.statements, visitor, isStatement, statementOffset));
// If the original body was a multi-line block, this must be a multi-line block.
if (!multiLine && body.multiLine) {
multiLine = true;
}
}
else {
Debug.assert(node.kind === SyntaxKind.ArrowFunction);
// To align with the old emitter, we use a synthetic end position on the location
// for the statement list we synthesize when we down-level an arrow function with
// an expression function body. This prevents both comments and source maps from
// being emitted for the end position only.
statementsLocation = moveRangeEnd(body, -1);
const equalsGreaterThanToken = (<ArrowFunction>node).equalsGreaterThanToken;
if (!nodeIsSynthesized(equalsGreaterThanToken) && !nodeIsSynthesized(body)) {
if (rangeEndIsOnSameLineAsRangeStart(equalsGreaterThanToken, body, currentSourceFile)) {
singleLine = true;
}
else {
multiLine = true;
}
}
const expression = visitNode(body, visitor, isExpression);
const returnStatement = createReturn(expression, /*location*/ body);
setEmitFlags(returnStatement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTrailingComments);
statements.push(returnStatement);
// To align with the source map emit for the old emitter, we set a custom
// source map location for the close brace.
closeBraceLocation = body;
}
const lexicalEnvironment = context.endLexicalEnvironment();
addRange(statements, lexicalEnvironment);
// If we added any final generated statements, this must be a multi-line block
if (!multiLine && lexicalEnvironment && lexicalEnvironment.length) {
multiLine = true;
}
const block = createBlock(createNodeArray(statements, statementsLocation), node.body, multiLine);
if (!multiLine && singleLine) {
setEmitFlags(block, EmitFlags.SingleLine);
}
if (closeBraceLocation) {
setTokenSourceMapRange(block, SyntaxKind.CloseBraceToken, closeBraceLocation);
}
setOriginalNode(block, node.body);
return block;
}
/**
* Adds a statement to capture the `this` of a function declaration if it is needed.
*
* @param statements The statements for the new function body.
* @param node A node.
*/
export function addCaptureThisForNodeIfNeeded(statements: Statement[], node: Node, enableSubstitutionsForCapturedThis: () => void): void {
if (node.transformFlags & TransformFlags.ContainsCapturedLexicalThis && node.kind !== SyntaxKind.ArrowFunction) {
captureThisForNode(statements, node, createThis(), enableSubstitutionsForCapturedThis);
}
}
export function captureThisForNode(statements: Statement[], node: Node, initializer: Expression | undefined, enableSubstitutionsForCapturedThis?: () => void, originalStatement?: Statement): void {
enableSubstitutionsForCapturedThis();
const captureThisStatement = createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList([
createVariableDeclaration(
"_this",
/*type*/ undefined,
initializer
)
]),
originalStatement
);
setEmitFlags(captureThisStatement, EmitFlags.NoComments | EmitFlags.CustomPrologue);
setSourceMapRange(captureThisStatement, node);
statements.push(captureThisStatement);
}
/**
* Gets a value indicating whether we need to add default value assignments for a
* function-like node.
*
* @param node A function-like node.
*/
function shouldAddDefaultValueAssignments(node: FunctionLikeDeclaration): boolean {
return (node.transformFlags & TransformFlags.ContainsDefaultValueAssignments) !== 0;
}
/**
* Adds statements to the body of a function-like node if it contains parameters with
* binding patterns or initializers.
*
* @param statements The statements for the new function body.
* @param node A function-like node.
*/
export function addDefaultValueAssignmentsIfNeeded(statements: Statement[],
node: FunctionLikeDeclaration,
visitor: (node: Node) => VisitResult<Node>,
convertObjectRest: boolean): void {
if (!shouldAddDefaultValueAssignments(node)) {
return;
}
for (const parameter of node.parameters) {
const { name, initializer, dotDotDotToken } = parameter;
// A rest parameter cannot have a binding pattern or an initializer,
// so let's just ignore it.
if (dotDotDotToken) {
continue;
}
if (isBindingPattern(name)) {
addDefaultValueAssignmentForBindingPattern(statements, parameter, name, initializer, visitor, convertObjectRest);
}
else if (initializer) {
addDefaultValueAssignmentForInitializer(statements, parameter, name, initializer, visitor);
}
}
}
/**
* Adds statements to the body of a function-like node for parameters with binding patterns
*
* @param statements The statements for the new function body.
* @param parameter The parameter for the function.
* @param name The name of the parameter.
* @param initializer The initializer for the parameter.
*/
function addDefaultValueAssignmentForBindingPattern(statements: Statement[],
parameter: ParameterDeclaration,
name: BindingPattern, initializer: Expression,
visitor: (node: Node) => VisitResult<Node>,
convertObjectRest: boolean): void {
const temp = getGeneratedNameForNode(parameter);
// In cases where a binding pattern is simply '[]' or '{}',
// we usually don't want to emit a var declaration; however, in the presence
// of an initializer, we must emit that expression to preserve side effects.
if (name.elements.length > 0) {
statements.push(
setEmitFlags(
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList(
flattenParameterDestructuring(parameter, temp, visitor, convertObjectRest)
)
),
EmitFlags.CustomPrologue
)
);
}
else if (initializer) {
statements.push(
setEmitFlags(
createStatement(
createAssignment(
temp,
visitNode(initializer, visitor, isExpression)
)
),
EmitFlags.CustomPrologue
)
);
}
}
/**
* Adds statements to the body of a function-like node for parameters with initializers.
*
* @param statements The statements for the new function body.
* @param parameter The parameter for the function.
* @param name The name of the parameter.
* @param initializer The initializer for the parameter.
*/
function addDefaultValueAssignmentForInitializer(statements: Statement[],
parameter: ParameterDeclaration,
name: Identifier,
initializer: Expression,
visitor: (node: Node) => VisitResult<Node>): void {
initializer = visitNode(initializer, visitor, isExpression);
const statement = createIf(
createStrictEquality(
getSynthesizedClone(name),
createVoidZero()
),
setEmitFlags(
createBlock([
createStatement(
createAssignment(
setEmitFlags(getMutableClone(name), EmitFlags.NoSourceMap),
setEmitFlags(initializer, EmitFlags.NoSourceMap | getEmitFlags(initializer)),
/*location*/ parameter
)
)
], /*location*/ parameter),
EmitFlags.SingleLine | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTokenSourceMaps
),
/*elseStatement*/ undefined,
/*location*/ parameter
);
statement.startsOnNewLine = true;
setEmitFlags(statement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.CustomPrologue);
statements.push(statement);
}
/**
* Gets a value indicating whether we need to add statements to handle a rest parameter.
*
* @param node A ParameterDeclaration node.
* @param inConstructorWithSynthesizedSuper A value indicating whether the parameter is
* part of a constructor declaration with a
* synthesized call to `super`
*/
function shouldAddRestParameter(node: ParameterDeclaration, inConstructorWithSynthesizedSuper: boolean) {
return node && node.dotDotDotToken && node.name.kind === SyntaxKind.Identifier && !inConstructorWithSynthesizedSuper;
}
/**
* Adds statements to the body of a function-like node if it contains a rest parameter.
*
* @param statements The statements for the new function body.
* @param node A function-like node.
* @param inConstructorWithSynthesizedSuper A value indicating whether the parameter is
* part of a constructor declaration with a
* synthesized call to `super`
*/
export function addRestParameterIfNeeded(statements: Statement[], node: FunctionLikeDeclaration, inConstructorWithSynthesizedSuper: boolean): void {
const parameter = lastOrUndefined(node.parameters);
if (!shouldAddRestParameter(parameter, inConstructorWithSynthesizedSuper)) {
return;
}
// `declarationName` is the name of the local declaration for the parameter.
const declarationName = getMutableClone(<Identifier>parameter.name);
setEmitFlags(declarationName, EmitFlags.NoSourceMap);
// `expressionName` is the name of the parameter used in expressions.
const expressionName = getSynthesizedClone(<Identifier>parameter.name);
const restIndex = node.parameters.length - 1;
const temp = createLoopVariable();
// var param = [];
statements.push(
setEmitFlags(
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList([
createVariableDeclaration(
declarationName,
/*type*/ undefined,
createArrayLiteral([])
)
]),
/*location*/ parameter
),
EmitFlags.CustomPrologue
)
);
// for (var _i = restIndex; _i < arguments.length; _i++) {
// param[_i - restIndex] = arguments[_i];
// }
const forStatement = createFor(
createVariableDeclarationList([
createVariableDeclaration(temp, /*type*/ undefined, createLiteral(restIndex))
], /*location*/ parameter),
createLessThan(
temp,
createPropertyAccess(createIdentifier("arguments"), "length"),
/*location*/ parameter
),
createPostfixIncrement(temp, /*location*/ parameter),
createBlock([
startOnNewLine(
createStatement(
createAssignment(
createElementAccess(
expressionName,
createSubtract(temp, createLiteral(restIndex))
),
createElementAccess(createIdentifier("arguments"), temp)
),
/*location*/ parameter
)
)
])
);
setEmitFlags(forStatement, EmitFlags.CustomPrologue);
startOnNewLine(forStatement);
statements.push(forStatement);
}
export function convertForOf(node: ForOfStatement, convertedLoopBodyStatements: Statement[],
visitor: (node: Node) => VisitResult<Node>,
enableSubstitutionsForBlockScopedBindings: () => void,
context: TransformationContext,
convertObjectRest?: boolean): ForStatement | ForOfStatement {
// The following ES6 code:
//
// for (let v of expr) { }
//
// should be emitted as
//
// for (var _i = 0, _a = expr; _i < _a.length; _i++) {
// var v = _a[_i];
// }
//
// where _a and _i are temps emitted to capture the RHS and the counter,
// respectively.
// When the left hand side is an expression instead of a let declaration,
// the "let v" is not emitted.
// When the left hand side is a let/const, the v is renamed if there is
// another v in scope.
// Note that all assignments to the LHS are emitted in the body, including
// all destructuring.
// Note also that because an extra statement is needed to assign to the LHS,
// for-of bodies are always emitted as blocks.
const expression = visitNode(node.expression, visitor, isExpression);
const initializer = node.initializer;
const statements: Statement[] = [];
// In the case where the user wrote an identifier as the RHS, like this:
//
// for (let v of arr) { }
//
// we don't want to emit a temporary variable for the RHS, just use it directly.
const counter = convertObjectRest ? undefined : createLoopVariable();
const rhsReference = expression.kind === SyntaxKind.Identifier
? createUniqueName((<Identifier>expression).text)
: createTempVariable(/*recordTempVariable*/ undefined);
const elementAccess = convertObjectRest ? rhsReference : createElementAccess(rhsReference, counter);
// Initialize LHS
// var v = _a[_i];
if (isVariableDeclarationList(initializer)) {
if (initializer.flags & NodeFlags.BlockScoped) {
enableSubstitutionsForBlockScopedBindings();
}
const firstOriginalDeclaration = firstOrUndefined(initializer.declarations);
if (firstOriginalDeclaration && isBindingPattern(firstOriginalDeclaration.name)) {
// This works whether the declaration is a var, let, or const.
// It will use rhsIterationValue _a[_i] as the initializer.
const declarations = flattenVariableDestructuring(
firstOriginalDeclaration,
elementAccess,
visitor,
/*recordTempVariable*/ undefined,
convertObjectRest
);
const declarationList = createVariableDeclarationList(declarations, /*location*/ initializer);
setOriginalNode(declarationList, initializer);
// Adjust the source map range for the first declaration to align with the old
// emitter.
const firstDeclaration = declarations[0];
const lastDeclaration = lastOrUndefined(declarations);
setSourceMapRange(declarationList, createRange(firstDeclaration.pos, lastDeclaration.end));
statements.push(
createVariableStatement(
/*modifiers*/ undefined,
declarationList
)
);
}
else {
// The following call does not include the initializer, so we have
// to emit it separately.
statements.push(
createVariableStatement(
/*modifiers*/ undefined,
setOriginalNode(
createVariableDeclarationList([
createVariableDeclaration(
firstOriginalDeclaration ? firstOriginalDeclaration.name : createTempVariable(/*recordTempVariable*/ undefined),
/*type*/ undefined,
createElementAccess(rhsReference, counter)
)
], /*location*/ moveRangePos(initializer, -1)),
initializer
),
/*location*/ moveRangeEnd(initializer, -1)
)
);
}
}
else {
// Initializer is an expression. Emit the expression in the body, so that it's
// evaluated on every iteration.
const assignment = createAssignment(initializer, elementAccess);
if (isDestructuringAssignment(assignment)) {
// This is a destructuring pattern, so we flatten the destructuring instead.
statements.push(
createStatement(
flattenDestructuringAssignment(
context,
assignment,
/*needsValue*/ false,
context.hoistVariableDeclaration,
visitor,
convertObjectRest
)
)
);
}
else {
// Currently there is not way to check that assignment is binary expression of destructing assignment
// so we have to cast never type to binaryExpression
(<BinaryExpression>assignment).end = initializer.end;
statements.push(createStatement(assignment, /*location*/ moveRangeEnd(initializer, -1)));
}
}
let bodyLocation: TextRange;
let statementsLocation: TextRange;
if (convertedLoopBodyStatements) {
addRange(statements, convertedLoopBodyStatements);
}
else {
const statement = visitNode(node.statement, visitor, isStatement);
if (isBlock(statement)) {
addRange(statements, statement.statements);
bodyLocation = statement;
statementsLocation = statement.statements;
}
else {
statements.push(statement);
}
}
// The old emitter does not emit source maps for the expression
setEmitFlags(expression, EmitFlags.NoSourceMap | getEmitFlags(expression));
// The old emitter does not emit source maps for the block.
// We add the location to preserve comments.
const body = createBlock(
createNodeArray(statements, /*location*/ statementsLocation),
/*location*/ bodyLocation
);
setEmitFlags(body, EmitFlags.NoSourceMap | EmitFlags.NoTokenSourceMaps);
let forStatement: ForStatement | ForOfStatement;
if (convertObjectRest) {
forStatement = createForOf(
createVariableDeclarationList([
createVariableDeclaration(rhsReference, /*type*/ undefined, /*initializer*/ undefined, /*location*/ node.expression)
], /*location*/ node.expression),
node.expression,
body,
/*location*/ node
);
}
else {
forStatement = createFor(
setEmitFlags(
createVariableDeclarationList([
createVariableDeclaration(counter, /*type*/ undefined, createLiteral(0), /*location*/ moveRangePos(node.expression, -1)),
createVariableDeclaration(rhsReference, /*type*/ undefined, expression, /*location*/ node.expression)
], /*location*/ node.expression),
EmitFlags.NoHoisting
),
createLessThan(
counter,
createPropertyAccess(rhsReference, "length"),
/*location*/ node.expression
),
createPostfixIncrement(counter, /*location*/ node.expression),
body,
/*location*/ node
);
}
// Disable trailing source maps for the OpenParenToken to align source map emit with the old emitter.
setEmitFlags(forStatement, EmitFlags.NoTokenTrailingSourceMaps);
return forStatement;
}
}

View File

@ -74,6 +74,8 @@ namespace ts {
visitNode(cbNode, (<ShorthandPropertyAssignment>node).questionToken) ||
visitNode(cbNode, (<ShorthandPropertyAssignment>node).equalsToken) ||
visitNode(cbNode, (<ShorthandPropertyAssignment>node).objectAssignmentInitializer);
case SyntaxKind.SpreadAssignment:
return visitNode(cbNode, (<SpreadAssignment>node).expression);
case SyntaxKind.Parameter:
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
@ -197,8 +199,8 @@ namespace ts {
visitNode(cbNode, (<ConditionalExpression>node).whenTrue) ||
visitNode(cbNode, (<ConditionalExpression>node).colonToken) ||
visitNode(cbNode, (<ConditionalExpression>node).whenFalse);
case SyntaxKind.SpreadElementExpression:
return visitNode(cbNode, (<SpreadElementExpression>node).expression);
case SyntaxKind.SpreadElement:
return visitNode(cbNode, (<SpreadElement>node).expression);
case SyntaxKind.Block:
case SyntaxKind.ModuleBlock:
return visitNodes(cbNodes, (<Block>node).statements);
@ -1269,9 +1271,11 @@ namespace ts {
// which would be a candidate for improved error reporting.
return token() === SyntaxKind.OpenBracketToken || isLiteralPropertyName();
case ParsingContext.ObjectLiteralMembers:
return token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.AsteriskToken || isLiteralPropertyName();
return token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.AsteriskToken || token() === SyntaxKind.DotDotDotToken || isLiteralPropertyName();
case ParsingContext.RestProperties:
return isLiteralPropertyName();
case ParsingContext.ObjectBindingElements:
return token() === SyntaxKind.OpenBracketToken || isLiteralPropertyName();
return token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.DotDotDotToken || isLiteralPropertyName();
case ParsingContext.HeritageClauseElement:
// If we see { } then only consume it as an expression if it is followed by , or {
// That way we won't consume the body of a class in its heritage clause.
@ -1398,6 +1402,7 @@ namespace ts {
case ParsingContext.ArrayBindingElements:
return token() === SyntaxKind.CloseBracketToken;
case ParsingContext.Parameters:
case ParsingContext.RestProperties:
// Tokens other than ')' and ']' (the latter for index signatures) are here for better error recovery
return token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.CloseBracketToken /*|| token === SyntaxKind.OpenBraceToken*/;
case ParsingContext.TypeArguments:
@ -1583,6 +1588,9 @@ namespace ts {
case ParsingContext.Parameters:
return isReusableParameter(node);
case ParsingContext.RestProperties:
return false;
// Any other lists we do not care about reusing nodes in. But feel free to add if
// you can do so safely. Danger areas involve nodes that may involve speculative
// parsing. If speculative parsing is involved with the node, then the range the
@ -1780,6 +1788,7 @@ namespace ts {
case ParsingContext.BlockStatements: return Diagnostics.Declaration_or_statement_expected;
case ParsingContext.SwitchClauses: return Diagnostics.case_or_default_expected;
case ParsingContext.SwitchClauseStatements: return Diagnostics.Statement_expected;
case ParsingContext.RestProperties: // fallthrough
case ParsingContext.TypeMembers: return Diagnostics.Property_or_signature_expected;
case ParsingContext.ClassMembers: return Diagnostics.Unexpected_token_A_constructor_method_accessor_or_property_was_expected;
case ParsingContext.EnumMembers: return Diagnostics.Enum_member_expected;
@ -4122,7 +4131,7 @@ namespace ts {
}
function parseSpreadElement(): Expression {
const node = <SpreadElementExpression>createNode(SyntaxKind.SpreadElementExpression);
const node = <SpreadElement>createNode(SyntaxKind.SpreadElement);
parseExpected(SyntaxKind.DotDotDotToken);
node.expression = parseAssignmentExpressionOrHigher();
return finishNode(node);
@ -4162,6 +4171,12 @@ namespace ts {
function parseObjectLiteralElement(): ObjectLiteralElementLike {
const fullStart = scanner.getStartPos();
const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
if (dotDotDotToken) {
const spreadElement = <SpreadAssignment>createNode(SyntaxKind.SpreadAssignment, fullStart);
spreadElement.expression = parseAssignmentExpressionOrHigher();
return addJSDocComment(finishNode(spreadElement));
}
const decorators = parseDecorators();
const modifiers = parseModifiers();
@ -4865,6 +4880,7 @@ namespace ts {
function parseObjectBindingElement(): BindingElement {
const node = <BindingElement>createNode(SyntaxKind.BindingElement);
node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
const tokenIsIdentifier = isIdentifier();
const propertyName = parsePropertyName();
if (tokenIsIdentifier && token() !== SyntaxKind.ColonToken) {
@ -5809,6 +5825,7 @@ namespace ts {
JsxChildren, // Things between opening and closing JSX tags
ArrayLiteralMembers, // Members in array literal
Parameters, // Parameters in parameter list
RestProperties, // Property names in a rest type list
TypeParameters, // Type parameters in type parameter list
TypeArguments, // Type arguments in type argument list
TupleElementTypes, // Element types in tuple element type list

View File

@ -1,6 +1,7 @@
/// <reference path="visitor.ts" />
/// <reference path="transformers/ts.ts" />
/// <reference path="transformers/jsx.ts" />
/// <reference path="transformers/esnext.ts" />
/// <reference path="transformers/es2017.ts" />
/// <reference path="transformers/es2016.ts" />
/// <reference path="transformers/es2015.ts" />
@ -116,6 +117,10 @@ namespace ts {
transformers.push(transformJsx);
}
if (languageVersion < ScriptTarget.ESNext) {
transformers.push(transformESNext);
}
if (languageVersion < ScriptTarget.ES2017) {
transformers.push(transformES2017);
}

View File

@ -17,7 +17,8 @@ namespace ts {
node: BinaryExpression,
needsValue: boolean,
recordTempVariable: (node: Identifier) => void,
visitor?: (node: Node) => VisitResult<Node>): Expression {
visitor?: (node: Node) => VisitResult<Node>,
transformRest?: boolean): Expression {
if (isEmptyObjectLiteralOrArrayLiteral(node.left)) {
const right = node.right;
@ -51,7 +52,7 @@ namespace ts {
location = value;
}
flattenDestructuring(node, value, location, emitAssignment, emitTempVariableAssignment, visitor);
flattenDestructuring(node, value, location, emitAssignment, emitTempVariableAssignment, recordTempVariable, emitRestAssignment, transformRest, visitor);
if (needsValue) {
expressions.push(value);
@ -61,7 +62,7 @@ namespace ts {
aggregateTransformFlags(expression);
return expression;
function emitAssignment(name: Identifier, value: Expression, location: TextRange) {
function emitAssignment(name: Identifier | ObjectLiteralExpression, value: Expression, location: TextRange) {
const expression = createAssignment(name, value, location);
// NOTE: this completely disables source maps, but aligns with the behavior of
@ -77,6 +78,10 @@ namespace ts {
emitAssignment(name, value, location);
return name;
}
function emitRestAssignment(elements: ObjectLiteralElementLike[], value: Expression, location: TextRange) {
emitAssignment(createObjectLiteral(elements), value, location);
}
}
/**
@ -89,14 +94,15 @@ namespace ts {
export function flattenParameterDestructuring(
node: ParameterDeclaration,
value: Expression,
visitor?: (node: Node) => VisitResult<Node>) {
visitor?: (node: Node) => VisitResult<Node>,
transformRest?: boolean) {
const declarations: VariableDeclaration[] = [];
flattenDestructuring(node, value, node, emitAssignment, emitTempVariableAssignment, visitor);
flattenDestructuring(node, value, node, emitAssignment, emitTempVariableAssignment, noop, emitRestAssignment, transformRest, visitor);
return declarations;
function emitAssignment(name: Identifier, value: Expression, location: TextRange) {
function emitAssignment(name: Identifier | BindingPattern, value: Expression, location: TextRange) {
const declaration = createVariableDeclaration(name, /*type*/ undefined, value, location);
// NOTE: this completely disables source maps, but aligns with the behavior of
@ -112,6 +118,10 @@ namespace ts {
emitAssignment(name, value, location);
return name;
}
function emitRestAssignment(elements: BindingElement[], value: Expression, location: TextRange) {
emitAssignment(createObjectBindingPattern(elements), value, location);
}
}
/**
@ -125,15 +135,16 @@ namespace ts {
node: VariableDeclaration,
value?: Expression,
visitor?: (node: Node) => VisitResult<Node>,
recordTempVariable?: (node: Identifier) => void) {
recordTempVariable?: (node: Identifier) => void,
transformRest?: boolean) {
const declarations: VariableDeclaration[] = [];
let pendingAssignments: Expression[];
flattenDestructuring(node, value, node, emitAssignment, emitTempVariableAssignment, visitor);
flattenDestructuring(node, value, node, emitAssignment, emitTempVariableAssignment, recordTempVariable, emitRestAssignment, transformRest, visitor);
return declarations;
function emitAssignment(name: Identifier, value: Expression, location: TextRange, original: Node) {
function emitAssignment(name: Identifier | BindingPattern, value: Expression, location: TextRange, original: Node) {
if (pendingAssignments) {
pendingAssignments.push(value);
value = inlineExpressions(pendingAssignments);
@ -167,6 +178,10 @@ namespace ts {
}
return name;
}
function emitRestAssignment(elements: BindingElement[], value: Expression, location: TextRange, original: Node) {
emitAssignment(createObjectBindingPattern(elements), value, location, original);
}
}
/**
@ -186,15 +201,17 @@ namespace ts {
const pendingAssignments: Expression[] = [];
flattenDestructuring(node, /*value*/ undefined, node, emitAssignment, emitTempVariableAssignment, visitor);
flattenDestructuring(node, /*value*/ undefined, node, emitAssignment, emitTempVariableAssignment, noop, emitRestAssignment, /*transformRest*/ false, visitor);
const expression = inlineExpressions(pendingAssignments);
aggregateTransformFlags(expression);
return expression;
function emitAssignment(name: Identifier, value: Expression, location: TextRange, original: Node) {
function emitAssignment(name: Identifier | ObjectLiteralExpression, value: Expression, location: TextRange, original: Node) {
const expression = createAssignmentCallback
? createAssignmentCallback(name, value, location)
? createAssignmentCallback(name.kind === SyntaxKind.Identifier ? name : emitTempVariableAssignment(name, location),
value,
location)
: createAssignment(name, value, location);
emitPendingAssignment(expression, original);
@ -206,6 +223,10 @@ namespace ts {
return name;
}
function emitRestAssignment(elements: ObjectLiteralElementLike[], value: Expression, location: TextRange, original: Node) {
emitAssignment(createObjectLiteral(elements), value, location, original);
}
function emitPendingAssignment(expression: Expression, original: Node) {
expression.original = original;
@ -223,6 +244,9 @@ namespace ts {
location: TextRange,
emitAssignment: (name: Identifier, value: Expression, location: TextRange, original: Node) => void,
emitTempVariableAssignment: (value: Expression, location: TextRange) => Identifier,
recordTempVariable: (node: Identifier) => void,
emitRestAssignment: (elements: (ObjectLiteralElementLike[] | BindingElement[]), value: Expression, location: TextRange, original: Node) => void,
transformRest: boolean,
visitor?: (node: Node) => VisitResult<Node>) {
if (value && visitor) {
value = visitNode(value, visitor, isExpression);
@ -284,23 +308,91 @@ namespace ts {
value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment);
}
for (const p of properties) {
let bindingElements: ObjectLiteralElementLike[] = [];
for (let i = 0; i < properties.length; i++) {
const p = properties[i];
if (p.kind === SyntaxKind.PropertyAssignment || p.kind === SyntaxKind.ShorthandPropertyAssignment) {
const propName = <Identifier | LiteralExpression>(<PropertyAssignment>p).name;
const target = p.kind === SyntaxKind.ShorthandPropertyAssignment ? <ShorthandPropertyAssignment>p : (<PropertyAssignment>p).initializer || propName;
// Assignment for target = value.propName should highligh whole property, hence use p as source map node
emitDestructuringAssignment(target, createDestructuringPropertyAccess(value, propName), p);
if (!transformRest ||
p.transformFlags & TransformFlags.ContainsSpreadExpression ||
(p.kind === SyntaxKind.PropertyAssignment && p.initializer.transformFlags & TransformFlags.ContainsSpreadExpression)) {
if (bindingElements.length) {
emitRestAssignment(bindingElements, value, location, target);
bindingElements = [];
}
const propName = <Identifier | LiteralExpression>(<PropertyAssignment>p).name;
const bindingTarget = p.kind === SyntaxKind.ShorthandPropertyAssignment ? <ShorthandPropertyAssignment>p : (<PropertyAssignment>p).initializer || propName;
// Assignment for bindingTarget = value.propName should highlight whole property, hence use p as source map node
emitDestructuringAssignment(bindingTarget, createDestructuringPropertyAccess(value, propName), p);
}
else {
bindingElements.push(p);
}
}
else if (i === properties.length - 1 && p.kind === SyntaxKind.SpreadAssignment) {
Debug.assert((p as SpreadAssignment).expression.kind === SyntaxKind.Identifier);
if (bindingElements.length) {
emitRestAssignment(bindingElements, value, location, target);
bindingElements = [];
}
const propName = (p as SpreadAssignment).expression as Identifier;
const restCall = createRestCall(value, target.properties, p => p.name, target);
emitDestructuringAssignment(propName, restCall, p);
}
}
if (bindingElements.length) {
emitRestAssignment(bindingElements, value, location, target);
bindingElements = [];
}
}
function emitArrayLiteralAssignment(target: ArrayLiteralExpression, value: Expression, location: TextRange) {
if (transformRest) {
emitESNextArrayLiteralAssignment(target, value, location);
}
else {
emitES2015ArrayLiteralAssignment(target, value, location);
}
}
function emitESNextArrayLiteralAssignment(target: ArrayLiteralExpression, value: Expression, location: TextRange) {
const elements = target.elements;
const numElements = elements.length;
if (numElements !== 1) {
// For anything but a single element destructuring we need to generate a temporary
// to ensure value is evaluated exactly once.
// When doing so we want to hightlight the passed in source map node since thats the one needing this temp assignment
// When doing so we want to highlight the passed-in source map node since thats the one needing this temp assignment
value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment);
}
const expressions: Expression[] = [];
const spreadContainingExpressions: [Expression, Identifier][] = [];
for (let i = 0; i < numElements; i++) {
const e = elements[i];
if (e.kind === SyntaxKind.OmittedExpression) {
continue;
}
if (e.transformFlags & TransformFlags.ContainsSpreadExpression && i < numElements - 1) {
const tmp = createTempVariable(recordTempVariable);
spreadContainingExpressions.push([e, tmp]);
expressions.push(tmp);
}
else {
expressions.push(e);
}
}
emitAssignment(updateArrayLiteral(target, expressions) as any as Identifier, value, undefined, undefined);
for (const [e, tmp] of spreadContainingExpressions) {
emitDestructuringAssignment(e, tmp, e);
}
}
function emitES2015ArrayLiteralAssignment(target: ArrayLiteralExpression, value: Expression, location: TextRange) {
const elements = target.elements;
const numElements = elements.length;
if (numElements !== 1) {
// For anything but a single element destructuring we need to generate a temporary
// to ensure value is evaluated exactly once.
// When doing so we want to highlight the passed-in source map node since thats the one needing this temp assignment
value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment);
}
@ -308,20 +400,41 @@ namespace ts {
const e = elements[i];
if (e.kind !== SyntaxKind.OmittedExpression) {
// Assignment for target = value.propName should highligh whole property, hence use e as source map node
if (e.kind !== SyntaxKind.SpreadElementExpression) {
if (e.kind !== SyntaxKind.SpreadElement) {
emitDestructuringAssignment(e, createElementAccess(value, createLiteral(i)), e);
}
else if (i === numElements - 1) {
emitDestructuringAssignment((<SpreadElementExpression>e).expression, createArraySlice(value, i), e);
emitDestructuringAssignment((<SpreadElement>e).expression, createArraySlice(value, i), e);
}
}
}
}
/** Given value: o, propName: p, pattern: { a, b, ...p } from the original statement
* `{ a, b, ...p } = o`, create `p = __rest(o, ["a", "b"]);`*/
function createRestCall<T extends Node>(value: Expression, elements: T[], getPropertyName: (element: T) => PropertyName, location: TextRange): Expression {
const propertyNames: LiteralExpression[] = [];
for (let i = 0; i < elements.length - 1; i++) {
if (isOmittedExpression(elements[i])) {
continue;
}
const str = <StringLiteral>createSynthesizedNode(SyntaxKind.StringLiteral);
str.pos = location.pos;
str.end = location.end;
str.text = getTextOfPropertyName(getPropertyName(elements[i]));
propertyNames.push(str);
}
const args = createSynthesizedNodeArray([value, createArrayLiteral(propertyNames, location)]);
return createCall(createIdentifier("__rest"), undefined, args);
}
function emitBindingElement(target: VariableDeclaration | ParameterDeclaration | BindingElement, value: Expression) {
// Any temporary assignments needed to emit target = value should point to target
const initializer = visitor ? visitNode(target.initializer, visitor, isExpression) : target.initializer;
if (initializer) {
if (transformRest) {
value = value || initializer;
}
else if (initializer) {
// Combine value and initializer
value = value ? createDefaultValueCheck(value, initializer, target) : initializer;
}
@ -331,9 +444,11 @@ namespace ts {
}
const name = target.name;
if (isBindingPattern(name)) {
const elements = name.elements;
const numElements = elements.length;
if (!isBindingPattern(name)) {
emitAssignment(name, value, target, target);
}
else {
const numElements = name.elements.length;
if (numElements !== 1) {
// For anything other than a single-element destructuring we need to generate a temporary
// to ensure value is evaluated exactly once. Additionally, if we have zero elements
@ -341,29 +456,104 @@ namespace ts {
// so in that case, we'll intentionally create that temporary.
value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ numElements !== 0, target, emitTempVariableAssignment);
}
for (let i = 0; i < numElements; i++) {
const element = elements[i];
if (isOmittedExpression(element)) {
continue;
}
else if (name.kind === SyntaxKind.ObjectBindingPattern) {
// Rewrite element to a declaration with an initializer that fetches property
const propName = element.propertyName || <Identifier>element.name;
emitBindingElement(element, createDestructuringPropertyAccess(value, propName));
}
else {
if (!element.dotDotDotToken) {
// Rewrite element to a declaration that accesses array element at index i
emitBindingElement(element, createElementAccess(value, i));
}
else if (i === numElements - 1) {
emitBindingElement(element, createArraySlice(value, i));
}
}
if (name.kind === SyntaxKind.ArrayBindingPattern) {
emitArrayBindingElement(name as ArrayBindingPattern, value);
}
else {
emitObjectBindingElement(target, value);
}
}
}
function emitArrayBindingElement(name: ArrayBindingPattern, value: Expression) {
if (transformRest) {
emitESNextArrayBindingElement(name, value);
}
else {
emitAssignment(name, value, target, target);
emitES2015ArrayBindingElement(name, value);
}
}
function emitES2015ArrayBindingElement(name: ArrayBindingPattern, value: Expression) {
const elements = name.elements;
const numElements = elements.length;
for (let i = 0; i < numElements; i++) {
const element = elements[i];
if (isOmittedExpression(element)) {
continue;
}
if (!element.dotDotDotToken) {
// Rewrite element to a declaration that accesses array element at index i
emitBindingElement(element, createElementAccess(value, i));
}
else if (i === numElements - 1) {
emitBindingElement(element, createArraySlice(value, i));
}
}
}
function emitESNextArrayBindingElement(name: ArrayBindingPattern, value: Expression) {
const elements = name.elements;
const numElements = elements.length;
const bindingElements: BindingElement[] = [];
const spreadContainingElements: BindingElement[] = [];
for (let i = 0; i < numElements; i++) {
const element = elements[i];
if (isOmittedExpression(element)) {
continue;
}
if (element.transformFlags & TransformFlags.ContainsSpreadExpression && i < numElements - 1) {
spreadContainingElements.push(element);
bindingElements.push(createBindingElement(undefined, undefined, getGeneratedNameForNode(element), undefined, value));
}
else {
bindingElements.push(element);
}
}
emitAssignment(updateArrayBindingPattern(name, bindingElements) as any as Identifier, value, undefined, undefined);
for (const element of spreadContainingElements) {
emitBindingElement(element, getGeneratedNameForNode(element));
}
}
function emitObjectBindingElement(target: VariableDeclaration | ParameterDeclaration | BindingElement, value: Expression) {
const name = target.name as BindingPattern;
const elements = name.elements;
const numElements = elements.length;
let bindingElements: BindingElement[] = [];
for (let i = 0; i < numElements; i++) {
const element = elements[i];
if (isOmittedExpression(element)) {
continue;
}
if (i === numElements - 1 && element.dotDotDotToken) {
if (bindingElements.length) {
emitRestAssignment(bindingElements, value, target, target);
bindingElements = [];
}
const restCall = createRestCall(value,
name.elements,
element => (element as BindingElement).propertyName || <Identifier>(element as BindingElement).name,
name);
emitBindingElement(element, restCall);
}
else if (transformRest && !(element.transformFlags & TransformFlags.ContainsSpreadExpression)) {
// do not emit until we have a complete bundle of ES2015 syntax
bindingElements.push(element);
}
else {
if (bindingElements.length) {
emitRestAssignment(bindingElements, value, target, target);
bindingElements = [];
}
// Rewrite element to a declaration with an initializer that fetches property
const propName = element.propertyName || <Identifier>element.name;
emitBindingElement(element, createDestructuringPropertyAccess(value, propName));
}
}
if (bindingElements.length) {
emitRestAssignment(bindingElements, value, target, target);
bindingElements = [];
}
}

View File

@ -861,7 +861,7 @@ namespace ts {
}
if (constructor) {
addDefaultValueAssignmentsIfNeeded(statements, constructor);
addDefaultValueAssignmentsIfNeeded(statements, constructor, visitor, /*convertObjectRest*/ false);
addRestParameterIfNeeded(statements, constructor, hasSynthesizedSuper);
Debug.assert(statementOffset >= 0, "statementOffset not initialized correctly!");
@ -954,7 +954,7 @@ namespace ts {
// If this isn't a derived class, just capture 'this' for arrow functions if necessary.
if (!hasExtendsClause) {
if (ctor) {
addCaptureThisForNodeIfNeeded(statements, ctor);
addCaptureThisForNodeIfNeeded(statements, ctor, enableSubstitutionsForCapturedThis);
}
return SuperCaptureResult.NoReplacement;
}
@ -1016,7 +1016,7 @@ namespace ts {
}
// Perform the capture.
captureThisForNode(statements, ctor, superCallExpression, firstStatement);
captureThisForNode(statements, ctor, superCallExpression, enableSubstitutionsForCapturedThis, firstStatement);
// If we're actually replacing the original statement, we need to signal this to the caller.
if (superCallExpression) {
@ -1085,242 +1085,6 @@ namespace ts {
}
}
/**
* Gets a value indicating whether we need to add default value assignments for a
* function-like node.
*
* @param node A function-like node.
*/
function shouldAddDefaultValueAssignments(node: FunctionLikeDeclaration): boolean {
return (node.transformFlags & TransformFlags.ContainsDefaultValueAssignments) !== 0;
}
/**
* Adds statements to the body of a function-like node if it contains parameters with
* binding patterns or initializers.
*
* @param statements The statements for the new function body.
* @param node A function-like node.
*/
function addDefaultValueAssignmentsIfNeeded(statements: Statement[], node: FunctionLikeDeclaration): void {
if (!shouldAddDefaultValueAssignments(node)) {
return;
}
for (const parameter of node.parameters) {
const { name, initializer, dotDotDotToken } = parameter;
// A rest parameter cannot have a binding pattern or an initializer,
// so let's just ignore it.
if (dotDotDotToken) {
continue;
}
if (isBindingPattern(name)) {
addDefaultValueAssignmentForBindingPattern(statements, parameter, name, initializer);
}
else if (initializer) {
addDefaultValueAssignmentForInitializer(statements, parameter, name, initializer);
}
}
}
/**
* Adds statements to the body of a function-like node for parameters with binding patterns
*
* @param statements The statements for the new function body.
* @param parameter The parameter for the function.
* @param name The name of the parameter.
* @param initializer The initializer for the parameter.
*/
function addDefaultValueAssignmentForBindingPattern(statements: Statement[], parameter: ParameterDeclaration, name: BindingPattern, initializer: Expression): void {
const temp = getGeneratedNameForNode(parameter);
// In cases where a binding pattern is simply '[]' or '{}',
// we usually don't want to emit a var declaration; however, in the presence
// of an initializer, we must emit that expression to preserve side effects.
if (name.elements.length > 0) {
statements.push(
setEmitFlags(
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList(
flattenParameterDestructuring(parameter, temp, visitor)
)
),
EmitFlags.CustomPrologue
)
);
}
else if (initializer) {
statements.push(
setEmitFlags(
createStatement(
createAssignment(
temp,
visitNode(initializer, visitor, isExpression)
)
),
EmitFlags.CustomPrologue
)
);
}
}
/**
* Adds statements to the body of a function-like node for parameters with initializers.
*
* @param statements The statements for the new function body.
* @param parameter The parameter for the function.
* @param name The name of the parameter.
* @param initializer The initializer for the parameter.
*/
function addDefaultValueAssignmentForInitializer(statements: Statement[], parameter: ParameterDeclaration, name: Identifier, initializer: Expression): void {
initializer = visitNode(initializer, visitor, isExpression);
const statement = createIf(
createStrictEquality(
getSynthesizedClone(name),
createVoidZero()
),
setEmitFlags(
createBlock([
createStatement(
createAssignment(
setEmitFlags(getMutableClone(name), EmitFlags.NoSourceMap),
setEmitFlags(initializer, EmitFlags.NoSourceMap | getEmitFlags(initializer)),
/*location*/ parameter
)
)
], /*location*/ parameter),
EmitFlags.SingleLine | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTokenSourceMaps
),
/*elseStatement*/ undefined,
/*location*/ parameter
);
statement.startsOnNewLine = true;
setEmitFlags(statement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.CustomPrologue);
statements.push(statement);
}
/**
* Gets a value indicating whether we need to add statements to handle a rest parameter.
*
* @param node A ParameterDeclaration node.
* @param inConstructorWithSynthesizedSuper A value indicating whether the parameter is
* part of a constructor declaration with a
* synthesized call to `super`
*/
function shouldAddRestParameter(node: ParameterDeclaration, inConstructorWithSynthesizedSuper: boolean) {
return node && node.dotDotDotToken && node.name.kind === SyntaxKind.Identifier && !inConstructorWithSynthesizedSuper;
}
/**
* Adds statements to the body of a function-like node if it contains a rest parameter.
*
* @param statements The statements for the new function body.
* @param node A function-like node.
* @param inConstructorWithSynthesizedSuper A value indicating whether the parameter is
* part of a constructor declaration with a
* synthesized call to `super`
*/
function addRestParameterIfNeeded(statements: Statement[], node: FunctionLikeDeclaration, inConstructorWithSynthesizedSuper: boolean): void {
const parameter = lastOrUndefined(node.parameters);
if (!shouldAddRestParameter(parameter, inConstructorWithSynthesizedSuper)) {
return;
}
// `declarationName` is the name of the local declaration for the parameter.
const declarationName = getMutableClone(<Identifier>parameter.name);
setEmitFlags(declarationName, EmitFlags.NoSourceMap);
// `expressionName` is the name of the parameter used in expressions.
const expressionName = getSynthesizedClone(<Identifier>parameter.name);
const restIndex = node.parameters.length - 1;
const temp = createLoopVariable();
// var param = [];
statements.push(
setEmitFlags(
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList([
createVariableDeclaration(
declarationName,
/*type*/ undefined,
createArrayLiteral([])
)
]),
/*location*/ parameter
),
EmitFlags.CustomPrologue
)
);
// for (var _i = restIndex; _i < arguments.length; _i++) {
// param[_i - restIndex] = arguments[_i];
// }
const forStatement = createFor(
createVariableDeclarationList([
createVariableDeclaration(temp, /*type*/ undefined, createLiteral(restIndex))
], /*location*/ parameter),
createLessThan(
temp,
createPropertyAccess(createIdentifier("arguments"), "length"),
/*location*/ parameter
),
createPostfixIncrement(temp, /*location*/ parameter),
createBlock([
startOnNewLine(
createStatement(
createAssignment(
createElementAccess(
expressionName,
createSubtract(temp, createLiteral(restIndex))
),
createElementAccess(createIdentifier("arguments"), temp)
),
/*location*/ parameter
)
)
])
);
setEmitFlags(forStatement, EmitFlags.CustomPrologue);
startOnNewLine(forStatement);
statements.push(forStatement);
}
/**
* Adds a statement to capture the `this` of a function declaration if it is needed.
*
* @param statements The statements for the new function body.
* @param node A node.
*/
function addCaptureThisForNodeIfNeeded(statements: Statement[], node: Node): void {
if (node.transformFlags & TransformFlags.ContainsCapturedLexicalThis && node.kind !== SyntaxKind.ArrowFunction) {
captureThisForNode(statements, node, createThis());
}
}
function captureThisForNode(statements: Statement[], node: Node, initializer: Expression | undefined, originalStatement?: Statement): void {
enableSubstitutionsForCapturedThis();
const captureThisStatement = createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList([
createVariableDeclaration(
"_this",
/*type*/ undefined,
initializer
)
]),
originalStatement
);
setEmitFlags(captureThisStatement, EmitFlags.NoComments | EmitFlags.CustomPrologue);
setSourceMapRange(captureThisStatement, node);
statements.push(captureThisStatement);
}
/**
* Adds statements to the class body function for a class to define the members of the
* class.
@ -1518,7 +1282,7 @@ namespace ts {
/*typeParameters*/ undefined,
visitNodes(node.parameters, visitor, isParameter),
/*type*/ undefined,
transformFunctionBody(node),
transformFunctionBody(node, visitor, currentSourceFile, context, enableSubstitutionsForCapturedThis),
/*location*/ node
),
/*original*/ node);
@ -1545,7 +1309,7 @@ namespace ts {
/*typeParameters*/ undefined,
visitNodes(node.parameters, visitor, isParameter),
/*type*/ undefined,
saveStateAndInvoke(node, transformFunctionBody),
saveStateAndInvoke(node, node => transformFunctionBody(node, visitor, currentSourceFile, context, enableSubstitutionsForCapturedThis)),
location
),
/*original*/ node
@ -1555,96 +1319,6 @@ namespace ts {
return expression;
}
/**
* Transforms the body of a function-like node.
*
* @param node A function-like node.
*/
function transformFunctionBody(node: FunctionLikeDeclaration) {
let multiLine = false; // indicates whether the block *must* be emitted as multiple lines
let singleLine = false; // indicates whether the block *may* be emitted as a single line
let statementsLocation: TextRange;
let closeBraceLocation: TextRange;
const statements: Statement[] = [];
const body = node.body;
let statementOffset: number;
startLexicalEnvironment();
if (isBlock(body)) {
// ensureUseStrict is false because no new prologue-directive should be added.
// addPrologueDirectives will simply put already-existing directives at the beginning of the target statement-array
statementOffset = addPrologueDirectives(statements, body.statements, /*ensureUseStrict*/ false, visitor);
}
addCaptureThisForNodeIfNeeded(statements, node);
addDefaultValueAssignmentsIfNeeded(statements, node);
addRestParameterIfNeeded(statements, node, /*inConstructorWithSynthesizedSuper*/ false);
// If we added any generated statements, this must be a multi-line block.
if (!multiLine && statements.length > 0) {
multiLine = true;
}
if (isBlock(body)) {
statementsLocation = body.statements;
addRange(statements, visitNodes(body.statements, visitor, isStatement, statementOffset));
// If the original body was a multi-line block, this must be a multi-line block.
if (!multiLine && body.multiLine) {
multiLine = true;
}
}
else {
Debug.assert(node.kind === SyntaxKind.ArrowFunction);
// To align with the old emitter, we use a synthetic end position on the location
// for the statement list we synthesize when we down-level an arrow function with
// an expression function body. This prevents both comments and source maps from
// being emitted for the end position only.
statementsLocation = moveRangeEnd(body, -1);
const equalsGreaterThanToken = (<ArrowFunction>node).equalsGreaterThanToken;
if (!nodeIsSynthesized(equalsGreaterThanToken) && !nodeIsSynthesized(body)) {
if (rangeEndIsOnSameLineAsRangeStart(equalsGreaterThanToken, body, currentSourceFile)) {
singleLine = true;
}
else {
multiLine = true;
}
}
const expression = visitNode(body, visitor, isExpression);
const returnStatement = createReturn(expression, /*location*/ body);
setEmitFlags(returnStatement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTrailingComments);
statements.push(returnStatement);
// To align with the source map emit for the old emitter, we set a custom
// source map location for the close brace.
closeBraceLocation = body;
}
const lexicalEnvironment = endLexicalEnvironment();
addRange(statements, lexicalEnvironment);
// If we added any final generated statements, this must be a multi-line block
if (!multiLine && lexicalEnvironment && lexicalEnvironment.length) {
multiLine = true;
}
const block = createBlock(createNodeArray(statements, statementsLocation), node.body, multiLine);
if (!multiLine && singleLine) {
setEmitFlags(block, EmitFlags.SingleLine);
}
if (closeBraceLocation) {
setTokenSourceMapRange(block, SyntaxKind.CloseBraceToken, closeBraceLocation);
}
setOriginalNode(block, node.body);
return block;
}
/**
* Visits an ExpressionStatement that contains a destructuring assignment.
*
@ -1926,171 +1600,7 @@ namespace ts {
}
function convertForOfToFor(node: ForOfStatement, convertedLoopBodyStatements: Statement[]): ForStatement {
// The following ES6 code:
//
// for (let v of expr) { }
//
// should be emitted as
//
// for (var _i = 0, _a = expr; _i < _a.length; _i++) {
// var v = _a[_i];
// }
//
// where _a and _i are temps emitted to capture the RHS and the counter,
// respectively.
// When the left hand side is an expression instead of a let declaration,
// the "let v" is not emitted.
// When the left hand side is a let/const, the v is renamed if there is
// another v in scope.
// Note that all assignments to the LHS are emitted in the body, including
// all destructuring.
// Note also that because an extra statement is needed to assign to the LHS,
// for-of bodies are always emitted as blocks.
const expression = visitNode(node.expression, visitor, isExpression);
const initializer = node.initializer;
const statements: Statement[] = [];
// In the case where the user wrote an identifier as the RHS, like this:
//
// for (let v of arr) { }
//
// we don't want to emit a temporary variable for the RHS, just use it directly.
const counter = createLoopVariable();
const rhsReference = expression.kind === SyntaxKind.Identifier
? createUniqueName((<Identifier>expression).text)
: createTempVariable(/*recordTempVariable*/ undefined);
// Initialize LHS
// var v = _a[_i];
if (isVariableDeclarationList(initializer)) {
if (initializer.flags & NodeFlags.BlockScoped) {
enableSubstitutionsForBlockScopedBindings();
}
const firstOriginalDeclaration = firstOrUndefined(initializer.declarations);
if (firstOriginalDeclaration && isBindingPattern(firstOriginalDeclaration.name)) {
// This works whether the declaration is a var, let, or const.
// It will use rhsIterationValue _a[_i] as the initializer.
const declarations = flattenVariableDestructuring(
firstOriginalDeclaration,
createElementAccess(rhsReference, counter),
visitor
);
const declarationList = createVariableDeclarationList(declarations, /*location*/ initializer);
setOriginalNode(declarationList, initializer);
// Adjust the source map range for the first declaration to align with the old
// emitter.
const firstDeclaration = declarations[0];
const lastDeclaration = lastOrUndefined(declarations);
setSourceMapRange(declarationList, createRange(firstDeclaration.pos, lastDeclaration.end));
statements.push(
createVariableStatement(
/*modifiers*/ undefined,
declarationList
)
);
}
else {
// The following call does not include the initializer, so we have
// to emit it separately.
statements.push(
createVariableStatement(
/*modifiers*/ undefined,
setOriginalNode(
createVariableDeclarationList([
createVariableDeclaration(
firstOriginalDeclaration ? firstOriginalDeclaration.name : createTempVariable(/*recordTempVariable*/ undefined),
/*type*/ undefined,
createElementAccess(rhsReference, counter)
)
], /*location*/ moveRangePos(initializer, -1)),
initializer
),
/*location*/ moveRangeEnd(initializer, -1)
)
);
}
}
else {
// Initializer is an expression. Emit the expression in the body, so that it's
// evaluated on every iteration.
const assignment = createAssignment(initializer, createElementAccess(rhsReference, counter));
if (isDestructuringAssignment(assignment)) {
// This is a destructuring pattern, so we flatten the destructuring instead.
statements.push(
createStatement(
flattenDestructuringAssignment(
context,
assignment,
/*needsValue*/ false,
hoistVariableDeclaration,
visitor
)
)
);
}
else {
// Currently there is not way to check that assignment is binary expression of destructing assignment
// so we have to cast never type to binaryExpression
(<BinaryExpression>assignment).end = initializer.end;
statements.push(createStatement(assignment, /*location*/ moveRangeEnd(initializer, -1)));
}
}
let bodyLocation: TextRange;
let statementsLocation: TextRange;
if (convertedLoopBodyStatements) {
addRange(statements, convertedLoopBodyStatements);
}
else {
const statement = visitNode(node.statement, visitor, isStatement);
if (isBlock(statement)) {
addRange(statements, statement.statements);
bodyLocation = statement;
statementsLocation = statement.statements;
}
else {
statements.push(statement);
}
}
// The old emitter does not emit source maps for the expression
setEmitFlags(expression, EmitFlags.NoSourceMap | getEmitFlags(expression));
// The old emitter does not emit source maps for the block.
// We add the location to preserve comments.
const body = createBlock(
createNodeArray(statements, /*location*/ statementsLocation),
/*location*/ bodyLocation
);
setEmitFlags(body, EmitFlags.NoSourceMap | EmitFlags.NoTokenSourceMaps);
const forStatement = createFor(
setEmitFlags(
createVariableDeclarationList([
createVariableDeclaration(counter, /*type*/ undefined, createLiteral(0), /*location*/ moveRangePos(node.expression, -1)),
createVariableDeclaration(rhsReference, /*type*/ undefined, expression, /*location*/ node.expression)
], /*location*/ node.expression),
EmitFlags.NoHoisting
),
createLessThan(
counter,
createPropertyAccess(rhsReference, "length"),
/*location*/ node.expression
),
createPostfixIncrement(counter, /*location*/ node.expression),
body,
/*location*/ node
);
// Disable trailing source maps for the OpenParenToken to align source map emit with the old emitter.
setEmitFlags(forStatement, EmitFlags.NoTokenTrailingSourceMaps);
return forStatement;
return <ForStatement>convertForOf(node, convertedLoopBodyStatements, visitor, enableSubstitutionsForBlockScopedBindings, context, /*transformRest*/ false);
}
/**
@ -2751,7 +2261,7 @@ namespace ts {
setEmitFlags(thisArg, EmitFlags.NoSubstitution);
}
let resultingCall: CallExpression | BinaryExpression;
if (node.transformFlags & TransformFlags.ContainsSpreadElementExpression) {
if (node.transformFlags & TransformFlags.ContainsSpreadExpression) {
// [source]
// f(...a, b)
// x.m(...a, b)
@ -2813,7 +2323,7 @@ namespace ts {
*/
function visitNewExpression(node: NewExpression): LeftHandSideExpression {
// We are here because we contain a SpreadElementExpression.
Debug.assert((node.transformFlags & TransformFlags.ContainsSpreadElementExpression) !== 0);
Debug.assert((node.transformFlags & TransformFlags.ContainsSpreadExpression) !== 0);
// [source]
// new C(...a)
@ -2834,7 +2344,7 @@ namespace ts {
}
/**
* Transforms an array of Expression nodes that contains a SpreadElementExpression.
* Transforms an array of Expression nodes that contains a SpreadExpression.
*
* @param elements The array of Expression nodes.
* @param needsUniqueCopy A value indicating whether to ensure that the result is a fresh array.
@ -2851,14 +2361,14 @@ namespace ts {
// expressions into an array literal.
const numElements = elements.length;
const segments = flatten(
spanMap(elements, partitionSpreadElement, (partition, visitPartition, _start, end) =>
spanMap(elements, partitionSpread, (partition, visitPartition, _start, end) =>
visitPartition(partition, multiLine, hasTrailingComma && end === numElements)
)
);
if (segments.length === 1) {
const firstElement = elements[0];
return needsUniqueCopy && isSpreadElementExpression(firstElement) && firstElement.expression.kind !== SyntaxKind.ArrayLiteralExpression
return needsUniqueCopy && isSpreadExpression(firstElement) && firstElement.expression.kind !== SyntaxKind.ArrayLiteralExpression
? createArraySlice(segments[0])
: segments[0];
}
@ -2867,17 +2377,17 @@ namespace ts {
return createArrayConcat(segments.shift(), segments);
}
function partitionSpreadElement(node: Expression) {
return isSpreadElementExpression(node)
? visitSpanOfSpreadElements
: visitSpanOfNonSpreadElements;
function partitionSpread(node: Expression) {
return isSpreadExpression(node)
? visitSpanOfSpreads
: visitSpanOfNonSpreads;
}
function visitSpanOfSpreadElements(chunk: Expression[]): VisitResult<Expression> {
return map(chunk, visitExpressionOfSpreadElement);
function visitSpanOfSpreads(chunk: Expression[]): VisitResult<Expression> {
return map(chunk, visitExpressionOfSpread);
}
function visitSpanOfNonSpreadElements(chunk: Expression[], multiLine: boolean, hasTrailingComma: boolean): VisitResult<Expression> {
function visitSpanOfNonSpreads(chunk: Expression[], multiLine: boolean, hasTrailingComma: boolean): VisitResult<Expression> {
return createArrayLiteral(
visitNodes(createNodeArray(chunk, /*location*/ undefined, hasTrailingComma), visitor, isExpression),
/*location*/ undefined,
@ -2886,11 +2396,11 @@ namespace ts {
}
/**
* Transforms the expression of a SpreadElementExpression node.
* Transforms the expression of a SpreadExpression node.
*
* @param node A SpreadElementExpression node.
* @param node A SpreadExpression node.
*/
function visitExpressionOfSpreadElement(node: SpreadElementExpression) {
function visitExpressionOfSpread(node: SpreadElement) {
return visitNode(node.expression, visitor, isExpression);
}
@ -3076,7 +2586,7 @@ namespace ts {
const statements: Statement[] = [];
startLexicalEnvironment();
addRange(statements, prologue);
addCaptureThisForNodeIfNeeded(statements, node);
addCaptureThisForNodeIfNeeded(statements, node, enableSubstitutionsForCapturedThis);
addRange(statements, visitNodes(createNodeArray(remaining), visitor, isStatement));
addRange(statements, endLexicalEnvironment());
const clone = getMutableClone(node);
@ -3266,11 +2776,11 @@ namespace ts {
}
const callArgument = singleOrUndefined((<CallExpression>statementExpression).arguments);
if (!callArgument || !nodeIsSynthesized(callArgument) || callArgument.kind !== SyntaxKind.SpreadElementExpression) {
if (!callArgument || !nodeIsSynthesized(callArgument) || callArgument.kind !== SyntaxKind.SpreadElement) {
return false;
}
const expression = (<SpreadElementExpression>callArgument).expression;
const expression = (<SpreadElement>callArgument).expression;
return isIdentifier(expression) && expression === parameter.name;
}
}

View File

@ -32,7 +32,6 @@ namespace ts {
switch (node.kind) {
case SyntaxKind.BinaryExpression:
return visitBinaryExpression(<BinaryExpression>node);
default:
Debug.failBadSyntaxKind(node);
return visitEachChild(node, visitor, context);

View File

@ -0,0 +1,272 @@
/// <reference path="../factory.ts" />
/// <reference path="../visitor.ts" />
/*@internal*/
namespace ts {
export function transformESNext(context: TransformationContext) {
const {
hoistVariableDeclaration,
} = context;
let currentSourceFile: SourceFile;
return transformSourceFile;
function transformSourceFile(node: SourceFile) {
currentSourceFile = node;
return visitEachChild(node, visitor, context);
}
function visitor(node: Node): VisitResult<Node> {
if (node.transformFlags & TransformFlags.ESNext) {
return visitorWorker(node);
}
else if (node.transformFlags & TransformFlags.ContainsESNext) {
return visitEachChild(node, visitor, context);
}
else {
return node;
}
}
function visitorWorker(node: Node): VisitResult<Node> {
switch (node.kind) {
case SyntaxKind.ObjectLiteralExpression:
return visitObjectLiteralExpression(node as ObjectLiteralExpression);
case SyntaxKind.BinaryExpression:
return visitBinaryExpression(node as BinaryExpression);
case SyntaxKind.VariableDeclaration:
return visitVariableDeclaration(node as VariableDeclaration);
case SyntaxKind.ForOfStatement:
return visitForOfStatement(node as ForOfStatement);
case SyntaxKind.ObjectBindingPattern:
case SyntaxKind.ArrayBindingPattern:
return node;
case SyntaxKind.FunctionDeclaration:
return visitFunctionDeclaration(node as FunctionDeclaration);
case SyntaxKind.FunctionExpression:
return visitFunctionExpression(node as FunctionExpression);
case SyntaxKind.ArrowFunction:
return visitArrowFunction(node as ArrowFunction);
case SyntaxKind.Parameter:
return visitParameter(node as ParameterDeclaration);
default:
Debug.failBadSyntaxKind(node);
return visitEachChild(node, visitor, context);
}
}
function chunkObjectLiteralElements(elements: ObjectLiteralElement[]): Expression[] {
let chunkObject: (ShorthandPropertyAssignment | PropertyAssignment)[];
const objects: Expression[] = [];
for (const e of elements) {
if (e.kind === SyntaxKind.SpreadAssignment) {
if (chunkObject) {
objects.push(createObjectLiteral(chunkObject));
chunkObject = undefined;
}
const target = (e as SpreadAssignment).expression;
objects.push(visitNode(target, visitor, isExpression));
}
else {
if (!chunkObject) {
chunkObject = [];
}
if (e.kind === SyntaxKind.PropertyAssignment) {
const p = e as PropertyAssignment;
chunkObject.push(createPropertyAssignment(p.name, visitNode(p.initializer, visitor, isExpression)));
}
else {
chunkObject.push(e as ShorthandPropertyAssignment);
}
}
}
if (chunkObject) {
objects.push(createObjectLiteral(chunkObject));
}
return objects;
}
function visitObjectLiteralExpression(node: ObjectLiteralExpression): Expression {
// spread elements emit like so:
// non-spread elements are chunked together into object literals, and then all are passed to __assign:
// { a, ...o, b } => __assign({a}, o, {b});
// If the first element is a spread element, then the first argument to __assign is {}:
// { ...o, a, b, ...o2 } => __assign({}, o, {a, b}, o2)
const objects = chunkObjectLiteralElements(node.properties);
if (objects.length && objects[0].kind !== SyntaxKind.ObjectLiteralExpression) {
objects.unshift(createObjectLiteral());
}
return createCall(createIdentifier("__assign"), undefined, objects);
}
/**
* Visits a BinaryExpression that contains a destructuring assignment.
*
* @param node A BinaryExpression node.
*/
function visitBinaryExpression(node: BinaryExpression): Expression {
if (isDestructuringAssignment(node) && node.left.transformFlags & TransformFlags.AssertESNext) {
return flattenDestructuringAssignment(context, node, /*needsDestructuringValue*/ true, hoistVariableDeclaration, visitor, /*transformRest*/ true);
}
return visitEachChild(node, visitor, context);
}
/**
* Visits a VariableDeclaration node with a binding pattern.
*
* @param node A VariableDeclaration node.
*/
function visitVariableDeclaration(node: VariableDeclaration): VisitResult<VariableDeclaration> {
// If we are here it is because the name contains a binding pattern with a rest somewhere in it.
if (isBindingPattern(node.name) && node.name.transformFlags & TransformFlags.AssertESNext) {
const result = flattenVariableDestructuring(node, /*value*/ undefined, visitor, /*recordTempVariable*/ undefined, /*transformRest*/ true);
return result;
}
return visitEachChild(node, visitor, context);
}
/**
* Visits a ForOfStatement and converts it into a ES2015-compatible ForOfStatement.
*
* @param node A ForOfStatement.
*/
function visitForOfStatement(node: ForOfStatement): VisitResult<Statement> {
// The following ESNext code:
//
// for (let { x, y, ...rest } of expr) { }
//
// should be emitted as
//
// for (var _a of expr) {
// let { x, y } = _a, rest = __rest(_a, ["x", "y"]);
// }
//
// where _a is a temp emitted to capture the RHS.
// When the left hand side is an expression instead of a let declaration,
// the `let` before the `{ x, y }` is not emitted.
// When the left hand side is a let/const, the v is renamed if there is
// another v in scope.
// Note that all assignments to the LHS are emitted in the body, including
// all destructuring.
// Note also that because an extra statement is needed to assign to the LHS,
// for-of bodies are always emitted as blocks.
// for (<init> of <expression>) <statement>
// where <init> is [let] variabledeclarationlist | expression
const initializer = node.initializer;
if (!isRestBindingPattern(initializer) && !isRestAssignment(initializer)) {
return visitEachChild(node, visitor, context);
}
return convertForOf(node, undefined, visitor, noop, context, /*transformRest*/ true);
}
function isRestBindingPattern(initializer: ForInitializer) {
if (isVariableDeclarationList(initializer)) {
const declaration = firstOrUndefined(initializer.declarations);
return declaration && declaration.name &&
declaration.name.kind === SyntaxKind.ObjectBindingPattern &&
!!(declaration.name.transformFlags & TransformFlags.ContainsSpreadExpression);
}
return false;
}
function isRestAssignment(initializer: ForInitializer) {
return initializer.kind === SyntaxKind.ObjectLiteralExpression &&
initializer.transformFlags & TransformFlags.ContainsSpreadExpression;
}
function visitParameter(node: ParameterDeclaration): ParameterDeclaration {
if (isObjectRestParameter(node)) {
// Binding patterns are converted into a generated name and are
// evaluated inside the function body.
return setOriginalNode(
createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined,
getGeneratedNameForNode(node),
/*questionToken*/ undefined,
/*type*/ undefined,
node.initializer,
/*location*/ node
),
/*original*/ node
);
}
else {
return node;
}
}
function isObjectRestParameter(node: ParameterDeclaration) {
return node.name &&
node.name.kind === SyntaxKind.ObjectBindingPattern &&
!!(node.name.transformFlags & TransformFlags.ContainsSpreadExpression);
}
function visitFunctionDeclaration(node: FunctionDeclaration): FunctionDeclaration {
const hasRest = forEach(node.parameters, isObjectRestParameter);
const body = hasRest ?
transformFunctionBody(node, visitor, currentSourceFile, context, noop, /*convertObjectRest*/ true) as Block :
visitEachChild(node.body, visitor, context);
return setOriginalNode(
createFunctionDeclaration(
/*decorators*/ undefined,
node.modifiers,
node.asteriskToken,
node.name,
/*typeParameters*/ undefined,
visitNodes(node.parameters, visitor, isParameter),
/*type*/ undefined,
body,
/*location*/ node
),
/*original*/ node);
}
function visitArrowFunction(node: ArrowFunction) {
const hasRest = forEach(node.parameters, isObjectRestParameter);
const body = hasRest ?
transformFunctionBody(node, visitor, currentSourceFile, context, noop, /*convertObjectRest*/ true) as Block :
visitEachChild(node.body, visitor, context);
const func = setOriginalNode(
createArrowFunction(
/*modifiers*/ undefined,
/*typeParameters*/ undefined,
visitNodes(node.parameters, visitor, isParameter),
/*type*/ undefined,
node.equalsGreaterThanToken,
body,
/*location*/ node
),
/*original*/ node
);
setEmitFlags(func, EmitFlags.CapturesThis);
return func;
}
function visitFunctionExpression(node: FunctionExpression): Expression {
const hasRest = forEach(node.parameters, isObjectRestParameter);
const body = hasRest ?
transformFunctionBody(node, visitor, currentSourceFile, context, noop, /*convertObjectRest*/ true) as Block :
visitEachChild(node.body, visitor, context);
return setOriginalNode(
createFunctionExpression(
/*modifiers*/ undefined,
node.asteriskToken,
name,
/*typeParameters*/ undefined,
visitNodes(node.parameters, visitor, isParameter),
/*type*/ undefined,
body,
/*location*/ node
),
/*original*/ node
);
}
}
}

View File

@ -1474,7 +1474,7 @@ namespace ts {
if (isAssignmentExpression(node)) {
return hasExportedReferenceInDestructuringTarget(node.left);
}
else if (isSpreadElementExpression(node)) {
else if (isSpreadExpression(node)) {
return hasExportedReferenceInDestructuringTarget(node.expression);
}
else if (isObjectLiteralExpression(node)) {

View File

@ -27,6 +27,7 @@
"visitor.ts",
"transformers/ts.ts",
"transformers/jsx.ts",
"transformers/esnext.ts",
"transformers/es2017.ts",
"transformers/es2016.ts",
"transformers/es2015.ts",

View File

@ -246,7 +246,7 @@ namespace ts {
ConditionalExpression,
TemplateExpression,
YieldExpression,
SpreadElementExpression,
SpreadElement,
ClassExpression,
OmittedExpression,
ExpressionWithTypeArguments,
@ -320,6 +320,7 @@ namespace ts {
// Property assignments
PropertyAssignment,
ShorthandPropertyAssignment,
SpreadAssignment,
// Enum
EnumMember,
@ -418,20 +419,21 @@ namespace ts {
HasDecorators = 1 << 11, // If the file has decorators (initialized by binding)
HasParamDecorators = 1 << 12, // If the file has parameter decorators (initialized by binding)
HasAsyncFunctions = 1 << 13, // If the file has async functions (initialized by binding)
HasJsxSpreadAttributes = 1 << 14, // If the file as JSX spread attributes (initialized by binding)
DisallowInContext = 1 << 15, // If node was parsed in a context where 'in-expressions' are not allowed
YieldContext = 1 << 16, // If node was parsed in the 'yield' context created when parsing a generator
DecoratorContext = 1 << 17, // If node was parsed as part of a decorator
AwaitContext = 1 << 18, // If node was parsed in the 'await' context created when parsing an async function
ThisNodeHasError = 1 << 19, // If the parser encountered an error when parsing the code that created this node
JavaScriptFile = 1 << 20, // If node was parsed in a JavaScript
ThisNodeOrAnySubNodesHasError = 1 << 21, // If this node or any of its children had an error
HasAggregatedChildData = 1 << 22, // If we've computed data from children and cached it in this node
HasSpreadAttribute = 1 << 14, // If the file as JSX spread attributes (initialized by binding)
HasRestAttribute = 1 << 15, // If the file has object destructure elements
DisallowInContext = 1 << 16, // If node was parsed in a context where 'in-expressions' are not allowed
YieldContext = 1 << 17, // If node was parsed in the 'yield' context created when parsing a generator
DecoratorContext = 1 << 18, // If node was parsed as part of a decorator
AwaitContext = 1 << 19, // If node was parsed in the 'await' context created when parsing an async function
ThisNodeHasError = 1 << 20, // If the parser encountered an error when parsing the code that created this node
JavaScriptFile = 1 << 21, // If node was parsed in a JavaScript
ThisNodeOrAnySubNodesHasError = 1 << 22, // If this node or any of its children had an error
HasAggregatedChildData = 1 << 23, // If we've computed data from children and cached it in this node
BlockScoped = Let | Const,
ReachabilityCheckFlags = HasImplicitReturn | HasExplicitReturn,
EmitHelperFlags = HasClassExtends | HasDecorators | HasParamDecorators | HasAsyncFunctions | HasJsxSpreadAttributes,
EmitHelperFlags = HasClassExtends | HasDecorators | HasParamDecorators | HasAsyncFunctions | HasSpreadAttribute,
ReachabilityAndEmitFlags = ReachabilityCheckFlags | EmitHelperFlags,
// Parsing context flags
@ -454,7 +456,6 @@ namespace ts {
Async = 1 << 8, // Property/Method/Function
Default = 1 << 9, // Function/Class (export default declaration)
Const = 1 << 11, // Variable declaration
HasComputedFlags = 1 << 29, // Modifier flags have been computed
AccessibilityModifier = Public | Private | Protected,
@ -649,7 +650,7 @@ namespace ts {
export interface BindingElement extends Declaration {
kind: SyntaxKind.BindingElement;
propertyName?: PropertyName; // Binding property name (in object binding pattern)
dotDotDotToken?: DotDotDotToken; // Present on rest binding element
dotDotDotToken?: DotDotDotToken; // Present on rest element (in object binding pattern)
name: BindingName; // Declared binding element name
initializer?: Expression; // Optional initializer
}
@ -675,7 +676,7 @@ namespace ts {
name?: PropertyName;
}
export type ObjectLiteralElementLike = PropertyAssignment | ShorthandPropertyAssignment | MethodDeclaration | AccessorDeclaration;
export type ObjectLiteralElementLike = PropertyAssignment | ShorthandPropertyAssignment | MethodDeclaration | AccessorDeclaration | SpreadAssignment;
export interface PropertyAssignment extends ObjectLiteralElement {
kind: SyntaxKind.PropertyAssignment;
@ -694,6 +695,11 @@ namespace ts {
objectAssignmentInitializer?: Expression;
}
export interface SpreadAssignment extends ObjectLiteralElement {
kind: SyntaxKind.SpreadAssignment;
expression: Expression;
}
// SyntaxKind.VariableDeclaration
// SyntaxKind.Parameter
// SyntaxKind.BindingElement
@ -1279,8 +1285,8 @@ namespace ts {
multiLine?: boolean;
}
export interface SpreadElementExpression extends Expression {
kind: SyntaxKind.SpreadElementExpression;
export interface SpreadElement extends Expression {
kind: SyntaxKind.SpreadElement;
expression: Expression;
}
@ -2381,6 +2387,12 @@ namespace ts {
CannotBeNamed
}
/* @internal */
export const enum SyntheticSymbolKind {
UnionOrIntersection,
Spread
}
export const enum TypePredicateKind {
This,
Identifier
@ -2592,7 +2604,9 @@ namespace ts {
instantiations?: Map<Type>; // Instantiations of generic type alias (undefined if non-generic)
mapper?: TypeMapper; // Type mapper for instantiation alias
referenced?: boolean; // True if alias symbol has been referenced as a value
containingType?: UnionOrIntersectionType; // Containing union or intersection type for synthetic property
containingType?: UnionOrIntersectionType; // Containing union or intersection type for synthetic property
leftSpread?: Symbol; // Left source for synthetic spread property
rightSpread?: Symbol; // Right source for synthetic spread property
hasNonUniformType?: boolean; // True if constituents have non-uniform types
isPartial?: boolean; // True if syntheric property of union type occurs in some but not all constituents
isDiscriminantProperty?: boolean; // True if discriminant synthetic property
@ -3163,7 +3177,8 @@ namespace ts {
ES2015 = 2,
ES2016 = 3,
ES2017 = 4,
Latest = ES2017,
ESNext = 5,
Latest = ESNext,
}
export const enum LanguageVariant {
@ -3478,32 +3493,34 @@ namespace ts {
ContainsTypeScript = 1 << 1,
Jsx = 1 << 2,
ContainsJsx = 1 << 3,
ES2017 = 1 << 4,
ContainsES2017 = 1 << 5,
ES2016 = 1 << 6,
ContainsES2016 = 1 << 7,
ES2015 = 1 << 8,
ContainsES2015 = 1 << 9,
Generator = 1 << 10,
ContainsGenerator = 1 << 11,
DestructuringAssignment = 1 << 12,
ContainsDestructuringAssignment = 1 << 13,
ESNext = 1 << 4,
ContainsESNext = 1 << 5,
ES2017 = 1 << 6,
ContainsES2017 = 1 << 7,
ES2016 = 1 << 8,
ContainsES2016 = 1 << 9,
ES2015 = 1 << 10,
ContainsES2015 = 1 << 11,
Generator = 1 << 12,
ContainsGenerator = 1 << 13,
DestructuringAssignment = 1 << 14,
ContainsDestructuringAssignment = 1 << 15,
// Markers
// - Flags used to indicate that a subtree contains a specific transformation.
ContainsDecorators = 1 << 14,
ContainsPropertyInitializer = 1 << 15,
ContainsLexicalThis = 1 << 16,
ContainsCapturedLexicalThis = 1 << 17,
ContainsLexicalThisInComputedPropertyName = 1 << 18,
ContainsDefaultValueAssignments = 1 << 19,
ContainsParameterPropertyAssignments = 1 << 20,
ContainsSpreadElementExpression = 1 << 21,
ContainsComputedPropertyName = 1 << 22,
ContainsBlockScopedBinding = 1 << 23,
ContainsBindingPattern = 1 << 24,
ContainsYield = 1 << 25,
ContainsHoistedDeclarationOrCompletion = 1 << 26,
ContainsDecorators = 1 << 16,
ContainsPropertyInitializer = 1 << 17,
ContainsLexicalThis = 1 << 18,
ContainsCapturedLexicalThis = 1 << 19,
ContainsLexicalThisInComputedPropertyName = 1 << 20,
ContainsDefaultValueAssignments = 1 << 21,
ContainsParameterPropertyAssignments = 1 << 22,
ContainsSpreadExpression = 1 << 23,
ContainsComputedPropertyName = 1 << 24,
ContainsBlockScopedBinding = 1 << 25,
ContainsBindingPattern = 1 << 26,
ContainsYield = 1 << 27,
ContainsHoistedDeclarationOrCompletion = 1 << 28,
HasComputedFlags = 1 << 29, // Transform flags have been computed.
@ -3511,6 +3528,7 @@ namespace ts {
// - Bitmasks that are used to assert facts about the syntax of a node and its subtree.
AssertTypeScript = TypeScript | ContainsTypeScript,
AssertJsx = Jsx | ContainsJsx,
AssertESNext = ESNext | ContainsESNext,
AssertES2017 = ES2017 | ContainsES2017,
AssertES2016 = ES2016 | ContainsES2016,
AssertES2015 = ES2015 | ContainsES2015,
@ -3520,7 +3538,7 @@ namespace ts {
// Scope Exclusions
// - Bitmasks that exclude flags from propagating out of a specific context
// into the subtree flags of their container.
NodeExcludes = TypeScript | Jsx | ES2017 | ES2016 | ES2015 | DestructuringAssignment | Generator | HasComputedFlags,
NodeExcludes = TypeScript | Jsx | ESNext | ES2017 | ES2016 | ES2015 | DestructuringAssignment | Generator | HasComputedFlags,
ArrowFunctionExcludes = NodeExcludes | ContainsDecorators | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion,
FunctionExcludes = NodeExcludes | ContainsDecorators | ContainsDefaultValueAssignments | ContainsCapturedLexicalThis | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion,
ConstructorExcludes = NodeExcludes | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion,
@ -3529,7 +3547,7 @@ namespace ts {
ModuleExcludes = NodeExcludes | ContainsDecorators | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding | ContainsHoistedDeclarationOrCompletion,
TypeExcludes = ~ContainsTypeScript,
ObjectLiteralExcludes = NodeExcludes | ContainsDecorators | ContainsComputedPropertyName | ContainsLexicalThisInComputedPropertyName,
ArrayLiteralOrCallOrNewExcludes = NodeExcludes | ContainsSpreadElementExpression,
ArrayLiteralOrCallOrNewExcludes = NodeExcludes | ContainsSpreadExpression,
VariableDeclarationListExcludes = NodeExcludes | ContainsBindingPattern,
ParameterExcludes = NodeExcludes | ContainsBindingPattern,

View File

@ -485,6 +485,22 @@ namespace ts {
return getFullWidth(name) === 0 ? "(Missing)" : getTextOfNode(name);
}
export function getTextOfPropertyName(name: PropertyName): string {
switch (name.kind) {
case SyntaxKind.Identifier:
return (<Identifier>name).text;
case SyntaxKind.StringLiteral:
case SyntaxKind.NumericLiteral:
return (<LiteralExpression>name).text;
case SyntaxKind.ComputedPropertyName:
if (isStringOrNumericLiteral((<ComputedPropertyName>name).expression.kind)) {
return (<LiteralExpression>(<ComputedPropertyName>name).expression).text;
}
}
return undefined;
}
export function entityNameToString(name: EntityNameOrEntityNameExpression): string {
switch (name.kind) {
case SyntaxKind.Identifier:
@ -1179,7 +1195,7 @@ namespace ts {
case SyntaxKind.PostfixUnaryExpression:
case SyntaxKind.BinaryExpression:
case SyntaxKind.ConditionalExpression:
case SyntaxKind.SpreadElementExpression:
case SyntaxKind.SpreadElement:
case SyntaxKind.TemplateExpression:
case SyntaxKind.NoSubstitutionTemplateLiteral:
case SyntaxKind.OmittedExpression:
@ -1641,7 +1657,7 @@ namespace ts {
return (<ForInStatement | ForOfStatement>parent).initializer === node ? AssignmentKind.Definite : AssignmentKind.None;
case SyntaxKind.ParenthesizedExpression:
case SyntaxKind.ArrayLiteralExpression:
case SyntaxKind.SpreadElementExpression:
case SyntaxKind.SpreadElement:
node = parent;
break;
case SyntaxKind.ShorthandPropertyAssignment:
@ -2226,7 +2242,7 @@ namespace ts {
case SyntaxKind.YieldExpression:
return 2;
case SyntaxKind.SpreadElementExpression:
case SyntaxKind.SpreadElement:
return 1;
default:
@ -3862,6 +3878,7 @@ namespace ts {
const kind = node.kind;
return kind === SyntaxKind.PropertyAssignment
|| kind === SyntaxKind.ShorthandPropertyAssignment
|| kind === SyntaxKind.SpreadAssignment
|| kind === SyntaxKind.MethodDeclaration
|| kind === SyntaxKind.GetAccessor
|| kind === SyntaxKind.SetAccessor
@ -3949,8 +3966,8 @@ namespace ts {
|| kind === SyntaxKind.NoSubstitutionTemplateLiteral;
}
export function isSpreadElementExpression(node: Node): node is SpreadElementExpression {
return node.kind === SyntaxKind.SpreadElementExpression;
export function isSpreadExpression(node: Node): node is SpreadElement {
return node.kind === SyntaxKind.SpreadElement;
}
export function isExpressionWithTypeArguments(node: Node): node is ExpressionWithTypeArguments {
@ -4008,7 +4025,7 @@ namespace ts {
|| kind === SyntaxKind.YieldExpression
|| kind === SyntaxKind.ArrowFunction
|| kind === SyntaxKind.BinaryExpression
|| kind === SyntaxKind.SpreadElementExpression
|| kind === SyntaxKind.SpreadElement
|| kind === SyntaxKind.AsExpression
|| kind === SyntaxKind.OmittedExpression
|| isUnaryExpressionKind(kind);
@ -4310,6 +4327,7 @@ namespace ts {
namespace ts {
export function getDefaultLibFileName(options: CompilerOptions): string {
switch (options.target) {
case ScriptTarget.ESNext:
case ScriptTarget.ES2017:
return "lib.es2017.d.ts";
case ScriptTarget.ES2016:

View File

@ -267,9 +267,9 @@ namespace ts {
case SyntaxKind.VoidExpression:
case SyntaxKind.AwaitExpression:
case SyntaxKind.YieldExpression:
case SyntaxKind.SpreadElementExpression:
case SyntaxKind.SpreadElement:
case SyntaxKind.NonNullExpression:
result = reduceNode((<ParenthesizedExpression | DeleteExpression | TypeOfExpression | VoidExpression | AwaitExpression | YieldExpression | SpreadElementExpression | NonNullExpression>node).expression, f, result);
result = reduceNode((<ParenthesizedExpression | DeleteExpression | TypeOfExpression | VoidExpression | AwaitExpression | YieldExpression | SpreadElement | NonNullExpression>node).expression, f, result);
break;
case SyntaxKind.PrefixUnaryExpression:
@ -510,6 +510,10 @@ namespace ts {
result = reduceNode((<ShorthandPropertyAssignment>node).objectAssignmentInitializer, f, result);
break;
case SyntaxKind.SpreadAssignment:
result = reduceNode((node as SpreadAssignment).expression, f, result);
break;
// Top-level nodes
case SyntaxKind.SourceFile:
result = reduceLeft((<SourceFile>node).statements, f, result);
@ -872,9 +876,9 @@ namespace ts {
return updateYield(<YieldExpression>node,
visitNode((<YieldExpression>node).expression, visitor, isExpression));
case SyntaxKind.SpreadElementExpression:
return updateSpread(<SpreadElementExpression>node,
visitNode((<SpreadElementExpression>node).expression, visitor, isExpression));
case SyntaxKind.SpreadElement:
return updateSpread(<SpreadElement>node,
visitNode((<SpreadElement>node).expression, visitor, isExpression));
case SyntaxKind.ClassExpression:
return updateClassExpression(<ClassExpression>node,
@ -1127,7 +1131,11 @@ namespace ts {
visitNode((<ShorthandPropertyAssignment>node).name, visitor, isIdentifier),
visitNode((<ShorthandPropertyAssignment>node).objectAssignmentInitializer, visitor, isExpression));
// Top-level nodes
case SyntaxKind.SpreadAssignment:
return updateSpreadAssignment(node as SpreadAssignment,
visitNode((node as SpreadAssignment).expression, visitor, isExpression));
// Top-level nodes
case SyntaxKind.SourceFile:
context.startLexicalEnvironment();
return updateSourceFileNode(<SourceFile>node,

View File

@ -1483,7 +1483,7 @@ namespace Harness {
}
if (typesError && symbolsError) {
throw new Error(typesError.message + ts.sys.newLine + symbolsError.message);
throw new Error(typesError.message + Harness.IO.newLine() + symbolsError.message);
}
if (typesError) {

View File

@ -29,6 +29,7 @@
"../compiler/visitor.ts",
"../compiler/transformers/ts.ts",
"../compiler/transformers/jsx.ts",
"../compiler/transformers/esnext.ts",
"../compiler/transformers/es2017.ts",
"../compiler/transformers/es2016.ts",
"../compiler/transformers/es2015.ts",

View File

@ -165,7 +165,7 @@ namespace ts {
start: undefined,
length: undefined,
}, {
messageText: "Argument for '--target' option must be: 'es3', 'es5', 'es6', 'es2015', 'es2016', 'es2017'",
messageText: "Argument for '--target' option must be: 'es3', 'es5', 'es6', 'es2015', 'es2016', 'es2017', 'esnext'",
category: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.category,
code: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.code,

View File

@ -176,7 +176,7 @@ namespace ts {
file: undefined,
start: 0,
length: 0,
messageText: "Argument for '--target' option must be: 'es3', 'es5', 'es6', 'es2015', 'es2016', 'es2017'",
messageText: "Argument for '--target' option must be: 'es3', 'es5', 'es6', 'es2015', 'es2016', 'es2017', 'esnext'",
code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category
}]

View File

@ -264,7 +264,7 @@ namespace ts.BreakpointResolver {
// a or ...c or d: x from
// [a, b, ...c] or { a, b } or { d: x } from destructuring pattern
if ((node.kind === SyntaxKind.Identifier ||
node.kind == SyntaxKind.SpreadElementExpression ||
node.kind == SyntaxKind.SpreadElement ||
node.kind === SyntaxKind.PropertyAssignment ||
node.kind === SyntaxKind.ShorthandPropertyAssignment) &&
isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent)) {

View File

@ -28,6 +28,7 @@
"../compiler/visitor.ts",
"../compiler/transformers/ts.ts",
"../compiler/transformers/jsx.ts",
"../compiler/transformers/esnext.ts",
"../compiler/transformers/es2017.ts",
"../compiler/transformers/es2016.ts",
"../compiler/transformers/es2015.ts",

View File

@ -530,8 +530,8 @@ namespace ts {
case SyntaxKind.DeleteExpression:
case SyntaxKind.VoidExpression:
case SyntaxKind.YieldExpression:
case SyntaxKind.SpreadElementExpression:
const unaryWordExpression = (<TypeOfExpression | DeleteExpression | VoidExpression | YieldExpression | SpreadElementExpression>n);
case SyntaxKind.SpreadElement:
const unaryWordExpression = n as (TypeOfExpression | DeleteExpression | VoidExpression | YieldExpression | SpreadElement);
return isCompletedNode(unaryWordExpression.expression, sourceFile);
case SyntaxKind.TaggedTemplateExpression:

View File

@ -5,16 +5,12 @@ tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAs
tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts(4,6): error TS2459: Type 'string | number | {}' has no property 'i1' and no string index signature.
tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts(5,12): error TS2525: Initializer provides no value for this binding element and the binding element has no default value.
tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts(5,21): error TS2353: Object literal may only specify known properties, and 'f212' does not exist in type '{ f21: any; }'.
tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts(6,7): error TS1180: Property destructuring pattern expected.
tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts(7,5): error TS2353: Object literal may only specify known properties, and 'a' does not exist in type '{ d1: any; }'.
tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts(7,11): error TS2353: Object literal may only specify known properties, and 'b' does not exist in type '{ d1: any; }'.
tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts(7,24): error TS2353: Object literal may only specify known properties, and 'e' does not exist in type '{ d1: any; }'.
tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts(9,7): error TS1005: ':' expected.
tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts(9,15): error TS1005: ':' expected.
tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts(10,12): error TS1005: ':' expected.
tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts(6,7): error TS1005: ':' expected.
tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts(6,15): error TS1005: ':' expected.
tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts(7,12): error TS1005: ':' expected.
==== tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts (13 errors) ====
==== tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAssignment3.ts (9 errors) ====
// Error
var {h?} = { h?: 1 };
~
@ -33,17 +29,6 @@ tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAs
!!! error TS2525: Initializer provides no value for this binding element and the binding element has no default value.
~~~~
!!! error TS2353: Object literal may only specify known properties, and 'f212' does not exist in type '{ f21: any; }'.
var { ...d1 } = {
~~~
!!! error TS1180: Property destructuring pattern expected.
a: 1, b: 1, d1: 9, e: 10
~
!!! error TS2353: Object literal may only specify known properties, and 'a' does not exist in type '{ d1: any; }'.
~
!!! error TS2353: Object literal may only specify known properties, and 'b' does not exist in type '{ d1: any; }'.
~
!!! error TS2353: Object literal may only specify known properties, and 'e' does not exist in type '{ d1: any; }'.
}
var {1} = { 1 };
~
!!! error TS1005: ':' expected.
@ -51,4 +36,5 @@ tests/cases/conformance/es6/destructuring/destructuringObjectBindingPatternAndAs
!!! error TS1005: ':' expected.
var {"prop"} = { "prop": 1 };
~
!!! error TS1005: ':' expected.
!!! error TS1005: ':' expected.

View File

@ -4,11 +4,9 @@ var {h?} = { h?: 1 };
var {i}: string | number = { i: 2 };
var {i1}: string | number| {} = { i1: 2 };
var { f2: {f21} = { f212: "string" } }: any = undefined;
var { ...d1 } = {
a: 1, b: 1, d1: 9, e: 10
}
var {1} = { 1 };
var {"prop"} = { "prop": 1 };
var {"prop"} = { "prop": 1 };
//// [destructuringObjectBindingPatternAndAssignment3.js]
// Error
@ -16,8 +14,5 @@ var h = { h: 1 }.h;
var i = { i: 2 }.i;
var i1 = { i1: 2 }.i1;
var _a = undefined.f2, f21 = (_a === void 0 ? { f212: "string" } : _a).f21;
var d1 = {
a: 1, b: 1, d1: 9, e: 10
}.d1;
var = { 1: }[1];
var = { "prop": 1 }["prop"];

View File

@ -0,0 +1,21 @@
tests/cases/conformance/types/spread/interfaceSpread.ts(2,5): error TS2698: Interface declaration cannot contain a spread property.
tests/cases/conformance/types/spread/interfaceSpread.ts(7,10): error TS2339: Property 'jam' does not exist on type 'Congealed<{ jam: number; }, { peanutButter: number; }>'.
tests/cases/conformance/types/spread/interfaceSpread.ts(8,10): error TS2339: Property 'peanutButter' does not exist on type 'Congealed<{ jam: number; }, { peanutButter: number; }>'.
==== tests/cases/conformance/types/spread/interfaceSpread.ts (3 errors) ====
interface Congealed<T, U> {
...T
~~~~
!!! error TS2698: Interface declaration cannot contain a spread property.
...U
}
let sandwich: Congealed<{jam: number }, { peanutButter: number }>;
sandwich.jam;
~~~
!!! error TS2339: Property 'jam' does not exist on type 'Congealed<{ jam: number; }, { peanutButter: number; }>'.
sandwich.peanutButter;
~~~~~~~~~~~~
!!! error TS2339: Property 'peanutButter' does not exist on type 'Congealed<{ jam: number; }, { peanutButter: number; }>'.

View File

@ -0,0 +1,15 @@
//// [interfaceSpread.ts]
interface Congealed<T, U> {
...T
...U
}
let sandwich: Congealed<{jam: number }, { peanutButter: number }>;
sandwich.jam;
sandwich.peanutButter;
//// [interfaceSpread.js]
var sandwich;
sandwich.jam;
sandwich.peanutButter;

View File

@ -0,0 +1,67 @@
//// [objectRest.ts]
let o = { a: 1, b: 'no' }
var { ...clone } = o;
var { a, ...justB } = o;
var { a, b: renamed, ...empty } = o;
var { ['b']: renamed, ...justA } = o;
var { 'b': renamed, ...justA } = o;
var { b: { '0': n, '1': oooo }, ...justA } = o;
let o2 = { c: 'terrible idea?', d: 'yes' };
var { d: renamed, ...d } = o2;
let nestedrest: { x: number, n1: { y: number, n2: { z: number, n3: { n4: number } } }, rest: number, restrest: number };
var { x, n1: { y, n2: { z, n3: { ...nr } } }, ...restrest } = nestedrest;
let complex: { x: { ka, ki }, y: number };
var { x: { ka, ...nested }, y: other, ...rest } = complex;
({x: { ka, ...nested }, y: other, ...rest} = complex);
var { x, ...fresh } = { x: 1, y: 2 };
({ x, ...fresh } = { x: 1, y: 2 });
class Removable {
private x: number;
protected y: number;
set z(value: number) { }
get both(): number { return 12 }
set both(value: number) { }
m() { }
removed: string;
remainder: string;
}
var removable = new Removable();
var { removed, ...removableRest } = removable;
//// [objectRest.js]
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && !e.indexOf(p))
t[p] = s[p];
return t;
};
let o = { a: 1, b: 'no' };
var clone = __rest(o, []);
var { a } = o, justB = __rest(o, ["a"]);
var { a, b: renamed } = o, empty = __rest(o, ["a", "b"]);
var { ['b']: renamed } = o, justA = __rest(o, ["b"]);
var { 'b': renamed } = o, justA = __rest(o, ["b"]);
var { b: { '0': n, '1': oooo } } = o, justA = __rest(o, ["b"]);
let o2 = { c: 'terrible idea?', d: 'yes' };
var { d: renamed } = o2, d = __rest(o2, ["d"]);
let nestedrest;
var { x } = nestedrest, _a = nestedrest.n1, { y } = _a, _b = _a.n2, { z } = _b, nr = __rest(_b.n3, []), restrest = __rest(nestedrest, ["x", "n1"]);
let complex;
var _c = complex.x, { ka } = _c, nested = __rest(_c, ["ka"]), { y: other } = complex, rest = __rest(complex, ["x", "y"]);
(_d = complex.x, { ka } = _d, nested = __rest(_d, ["ka"]), { y: other } = complex, rest = __rest(complex, ["x", "y"]), complex);
var _e = { x: 1, y: 2 }, { x } = _e, fresh = __rest(_e, ["x"]);
(_f = { x: 1, y: 2 }, { x } = _f, fresh = __rest(_f, ["x"]), _f);
class Removable {
set z(value) { }
get both() { return 12; }
set both(value) { }
m() { }
}
var removable = new Removable();
var { removed } = removable, removableRest = __rest(removable, ["removed"]);
var _d, _f;

View File

@ -0,0 +1,146 @@
=== tests/cases/conformance/types/rest/objectRest.ts ===
let o = { a: 1, b: 'no' }
>o : Symbol(o, Decl(objectRest.ts, 0, 3))
>a : Symbol(a, Decl(objectRest.ts, 0, 9))
>b : Symbol(b, Decl(objectRest.ts, 0, 15))
var { ...clone } = o;
>clone : Symbol(clone, Decl(objectRest.ts, 1, 5))
>o : Symbol(o, Decl(objectRest.ts, 0, 3))
var { a, ...justB } = o;
>a : Symbol(a, Decl(objectRest.ts, 2, 5), Decl(objectRest.ts, 3, 5))
>justB : Symbol(justB, Decl(objectRest.ts, 2, 8))
>o : Symbol(o, Decl(objectRest.ts, 0, 3))
var { a, b: renamed, ...empty } = o;
>a : Symbol(a, Decl(objectRest.ts, 2, 5), Decl(objectRest.ts, 3, 5))
>b : Symbol(b, Decl(objectRest.ts, 0, 15))
>renamed : Symbol(renamed, Decl(objectRest.ts, 3, 8), Decl(objectRest.ts, 4, 5), Decl(objectRest.ts, 5, 5), Decl(objectRest.ts, 9, 5))
>empty : Symbol(empty, Decl(objectRest.ts, 3, 20))
>o : Symbol(o, Decl(objectRest.ts, 0, 3))
var { ['b']: renamed, ...justA } = o;
>'b' : Symbol(renamed, Decl(objectRest.ts, 3, 8), Decl(objectRest.ts, 4, 5), Decl(objectRest.ts, 5, 5), Decl(objectRest.ts, 9, 5))
>renamed : Symbol(renamed, Decl(objectRest.ts, 3, 8), Decl(objectRest.ts, 4, 5), Decl(objectRest.ts, 5, 5), Decl(objectRest.ts, 9, 5))
>justA : Symbol(justA, Decl(objectRest.ts, 4, 21), Decl(objectRest.ts, 5, 19), Decl(objectRest.ts, 6, 31))
>o : Symbol(o, Decl(objectRest.ts, 0, 3))
var { 'b': renamed, ...justA } = o;
>renamed : Symbol(renamed, Decl(objectRest.ts, 3, 8), Decl(objectRest.ts, 4, 5), Decl(objectRest.ts, 5, 5), Decl(objectRest.ts, 9, 5))
>justA : Symbol(justA, Decl(objectRest.ts, 4, 21), Decl(objectRest.ts, 5, 19), Decl(objectRest.ts, 6, 31))
>o : Symbol(o, Decl(objectRest.ts, 0, 3))
var { b: { '0': n, '1': oooo }, ...justA } = o;
>b : Symbol(b, Decl(objectRest.ts, 0, 15))
>n : Symbol(n, Decl(objectRest.ts, 6, 10))
>oooo : Symbol(oooo, Decl(objectRest.ts, 6, 18))
>justA : Symbol(justA, Decl(objectRest.ts, 4, 21), Decl(objectRest.ts, 5, 19), Decl(objectRest.ts, 6, 31))
>o : Symbol(o, Decl(objectRest.ts, 0, 3))
let o2 = { c: 'terrible idea?', d: 'yes' };
>o2 : Symbol(o2, Decl(objectRest.ts, 8, 3))
>c : Symbol(c, Decl(objectRest.ts, 8, 10))
>d : Symbol(d, Decl(objectRest.ts, 8, 31))
var { d: renamed, ...d } = o2;
>d : Symbol(d, Decl(objectRest.ts, 8, 31))
>renamed : Symbol(renamed, Decl(objectRest.ts, 3, 8), Decl(objectRest.ts, 4, 5), Decl(objectRest.ts, 5, 5), Decl(objectRest.ts, 9, 5))
>d : Symbol(d, Decl(objectRest.ts, 9, 17))
>o2 : Symbol(o2, Decl(objectRest.ts, 8, 3))
let nestedrest: { x: number, n1: { y: number, n2: { z: number, n3: { n4: number } } }, rest: number, restrest: number };
>nestedrest : Symbol(nestedrest, Decl(objectRest.ts, 11, 3))
>x : Symbol(x, Decl(objectRest.ts, 11, 17))
>n1 : Symbol(n1, Decl(objectRest.ts, 11, 28))
>y : Symbol(y, Decl(objectRest.ts, 11, 34))
>n2 : Symbol(n2, Decl(objectRest.ts, 11, 45))
>z : Symbol(z, Decl(objectRest.ts, 11, 51))
>n3 : Symbol(n3, Decl(objectRest.ts, 11, 62))
>n4 : Symbol(n4, Decl(objectRest.ts, 11, 68))
>rest : Symbol(rest, Decl(objectRest.ts, 11, 86))
>restrest : Symbol(restrest, Decl(objectRest.ts, 11, 100))
var { x, n1: { y, n2: { z, n3: { ...nr } } }, ...restrest } = nestedrest;
>x : Symbol(x, Decl(objectRest.ts, 12, 5), Decl(objectRest.ts, 17, 5))
>n1 : Symbol(n1, Decl(objectRest.ts, 11, 28))
>y : Symbol(y, Decl(objectRest.ts, 12, 14))
>n2 : Symbol(n2, Decl(objectRest.ts, 11, 45))
>z : Symbol(z, Decl(objectRest.ts, 12, 23))
>n3 : Symbol(n3, Decl(objectRest.ts, 11, 62))
>nr : Symbol(nr, Decl(objectRest.ts, 12, 32))
>restrest : Symbol(restrest, Decl(objectRest.ts, 12, 45))
>nestedrest : Symbol(nestedrest, Decl(objectRest.ts, 11, 3))
let complex: { x: { ka, ki }, y: number };
>complex : Symbol(complex, Decl(objectRest.ts, 14, 3))
>x : Symbol(x, Decl(objectRest.ts, 14, 14))
>ka : Symbol(ka, Decl(objectRest.ts, 14, 19))
>ki : Symbol(ki, Decl(objectRest.ts, 14, 23))
>y : Symbol(y, Decl(objectRest.ts, 14, 29))
var { x: { ka, ...nested }, y: other, ...rest } = complex;
>x : Symbol(x, Decl(objectRest.ts, 14, 14))
>ka : Symbol(ka, Decl(objectRest.ts, 15, 10))
>nested : Symbol(nested, Decl(objectRest.ts, 15, 14))
>y : Symbol(y, Decl(objectRest.ts, 14, 29))
>other : Symbol(other, Decl(objectRest.ts, 15, 27))
>rest : Symbol(rest, Decl(objectRest.ts, 15, 37))
>complex : Symbol(complex, Decl(objectRest.ts, 14, 3))
({x: { ka, ...nested }, y: other, ...rest} = complex);
>x : Symbol(x, Decl(objectRest.ts, 16, 2))
>ka : Symbol(ka, Decl(objectRest.ts, 16, 6))
>y : Symbol(y, Decl(objectRest.ts, 16, 23))
>other : Symbol(other, Decl(objectRest.ts, 15, 27))
>complex : Symbol(complex, Decl(objectRest.ts, 14, 3))
var { x, ...fresh } = { x: 1, y: 2 };
>x : Symbol(x, Decl(objectRest.ts, 12, 5), Decl(objectRest.ts, 17, 5))
>fresh : Symbol(fresh, Decl(objectRest.ts, 17, 8))
>x : Symbol(x, Decl(objectRest.ts, 17, 23))
>y : Symbol(y, Decl(objectRest.ts, 17, 29))
({ x, ...fresh } = { x: 1, y: 2 });
>x : Symbol(x, Decl(objectRest.ts, 18, 2))
>x : Symbol(x, Decl(objectRest.ts, 18, 20))
>y : Symbol(y, Decl(objectRest.ts, 18, 26))
class Removable {
>Removable : Symbol(Removable, Decl(objectRest.ts, 18, 35))
private x: number;
>x : Symbol(Removable.x, Decl(objectRest.ts, 20, 17))
protected y: number;
>y : Symbol(Removable.y, Decl(objectRest.ts, 21, 22))
set z(value: number) { }
>z : Symbol(Removable.z, Decl(objectRest.ts, 22, 24))
>value : Symbol(value, Decl(objectRest.ts, 23, 10))
get both(): number { return 12 }
>both : Symbol(Removable.both, Decl(objectRest.ts, 23, 28), Decl(objectRest.ts, 24, 36))
set both(value: number) { }
>both : Symbol(Removable.both, Decl(objectRest.ts, 23, 28), Decl(objectRest.ts, 24, 36))
>value : Symbol(value, Decl(objectRest.ts, 25, 13))
m() { }
>m : Symbol(Removable.m, Decl(objectRest.ts, 25, 31))
removed: string;
>removed : Symbol(Removable.removed, Decl(objectRest.ts, 26, 11))
remainder: string;
>remainder : Symbol(Removable.remainder, Decl(objectRest.ts, 27, 20))
}
var removable = new Removable();
>removable : Symbol(removable, Decl(objectRest.ts, 30, 3))
>Removable : Symbol(Removable, Decl(objectRest.ts, 18, 35))
var { removed, ...removableRest } = removable;
>removed : Symbol(removed, Decl(objectRest.ts, 31, 5))
>removableRest : Symbol(removableRest, Decl(objectRest.ts, 31, 14))
>removable : Symbol(removable, Decl(objectRest.ts, 30, 3))

View File

@ -0,0 +1,170 @@
=== tests/cases/conformance/types/rest/objectRest.ts ===
let o = { a: 1, b: 'no' }
>o : { a: number; b: string; }
>{ a: 1, b: 'no' } : { a: number; b: string; }
>a : number
>1 : 1
>b : string
>'no' : "no"
var { ...clone } = o;
>clone : { a: number; b: string; }
>o : { a: number; b: string; }
var { a, ...justB } = o;
>a : number
>justB : { b: string; }
>o : { a: number; b: string; }
var { a, b: renamed, ...empty } = o;
>a : number
>b : any
>renamed : string
>empty : {}
>o : { a: number; b: string; }
var { ['b']: renamed, ...justA } = o;
>'b' : "b"
>renamed : string
>justA : { a: number; }
>o : { a: number; b: string; }
var { 'b': renamed, ...justA } = o;
>renamed : string
>justA : { a: number; }
>o : { a: number; b: string; }
var { b: { '0': n, '1': oooo }, ...justA } = o;
>b : any
>n : string
>oooo : string
>justA : { a: number; }
>o : { a: number; b: string; }
let o2 = { c: 'terrible idea?', d: 'yes' };
>o2 : { c: string; d: string; }
>{ c: 'terrible idea?', d: 'yes' } : { c: string; d: string; }
>c : string
>'terrible idea?' : "terrible idea?"
>d : string
>'yes' : "yes"
var { d: renamed, ...d } = o2;
>d : any
>renamed : string
>d : { c: string; }
>o2 : { c: string; d: string; }
let nestedrest: { x: number, n1: { y: number, n2: { z: number, n3: { n4: number } } }, rest: number, restrest: number };
>nestedrest : { x: number; n1: { y: number; n2: { z: number; n3: { n4: number; }; }; }; rest: number; restrest: number; }
>x : number
>n1 : { y: number; n2: { z: number; n3: { n4: number; }; }; }
>y : number
>n2 : { z: number; n3: { n4: number; }; }
>z : number
>n3 : { n4: number; }
>n4 : number
>rest : number
>restrest : number
var { x, n1: { y, n2: { z, n3: { ...nr } } }, ...restrest } = nestedrest;
>x : number
>n1 : any
>y : number
>n2 : any
>z : number
>n3 : any
>nr : { n4: number; }
>restrest : { rest: number; restrest: number; }
>nestedrest : { x: number; n1: { y: number; n2: { z: number; n3: { n4: number; }; }; }; rest: number; restrest: number; }
let complex: { x: { ka, ki }, y: number };
>complex : { x: { ka: any; ki: any; }; y: number; }
>x : { ka: any; ki: any; }
>ka : any
>ki : any
>y : number
var { x: { ka, ...nested }, y: other, ...rest } = complex;
>x : any
>ka : any
>nested : { ki: any; }
>y : any
>other : number
>rest : {}
>complex : { x: { ka: any; ki: any; }; y: number; }
({x: { ka, ...nested }, y: other, ...rest} = complex);
>({x: { ka, ...nested }, y: other, ...rest} = complex) : { x: { ka: any; ki: any; }; y: number; }
>{x: { ka, ...nested }, y: other, ...rest} = complex : { x: { ka: any; ki: any; }; y: number; }
>{x: { ka, ...nested }, y: other, ...rest} : { x: { ki: any; ka: any; }; y: number; }
>x : { ki: any; ka: any; }
>{ ka, ...nested } : { ki: any; ka: any; }
>ka : any
>nested : any
>y : number
>other : number
>rest : any
>complex : { x: { ka: any; ki: any; }; y: number; }
var { x, ...fresh } = { x: 1, y: 2 };
>x : number
>fresh : { y: number; }
>{ x: 1, y: 2 } : { x: number; y: number; }
>x : number
>1 : 1
>y : number
>2 : 2
({ x, ...fresh } = { x: 1, y: 2 });
>({ x, ...fresh } = { x: 1, y: 2 }) : { x: number; y: number; }
>{ x, ...fresh } = { x: 1, y: 2 } : { x: number; y: number; }
>{ x, ...fresh } : { y: number; x: number; }
>x : number
>fresh : any
>{ x: 1, y: 2 } : { x: number; y: number; }
>x : number
>1 : 1
>y : number
>2 : 2
class Removable {
>Removable : Removable
private x: number;
>x : number
protected y: number;
>y : number
set z(value: number) { }
>z : number
>value : number
get both(): number { return 12 }
>both : number
>12 : 12
set both(value: number) { }
>both : number
>value : number
m() { }
>m : () => void
removed: string;
>removed : string
remainder: string;
>remainder : string
}
var removable = new Removable();
>removable : Removable
>new Removable() : Removable
>Removable : typeof Removable
var { removed, ...removableRest } = removable;
>removed : string
>removableRest : { both: number; remainder: string; }
>removable : Removable

View File

@ -0,0 +1,35 @@
//// [objectRestAssignment.ts]
let ka: any;
let nested: { ki };
let other: number;
let rest: { };
let complex: { x: { ka, ki }, y: number };
({x: { ka, ...nested }, y: other, ...rest} = complex);
// should be:
let overEmit: { a: { ka: string, x: string }[], b: { z: string, ki: string, ku: string }, ke: string, ko: string };
// var _g = overEmit.a, [_h, ...y] = _g, nested2 = __rest(_h, []), _j = overEmit.b, { z } = _j, c = __rest(_j, ["z"]), rest2 = __rest(overEmit, ["a", "b"]);
var { a: [{ ...nested2 }, ...y], b: { z, ...c }, ...rest2 } = overEmit;
({ a: [{ ...nested2 }, ...y], b: { z, ...c }, ...rest2 } = overEmit);
//// [objectRestAssignment.js]
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && !e.indexOf(p))
t[p] = s[p];
return t;
};
let ka;
let nested;
let other;
let rest;
let complex;
(_a = complex.x, { ka } = _a, nested = __rest(_a, ["ka"]), { y: other } = complex, rest = __rest(complex, ["x", "y"]), complex);
// should be:
let overEmit;
// var _g = overEmit.a, [_h, ...y] = _g, nested2 = __rest(_h, []), _j = overEmit.b, { z } = _j, c = __rest(_j, ["z"]), rest2 = __rest(overEmit, ["a", "b"]);
var _b = overEmit.a, [_c, ...y] = _b, nested2 = __rest(_c, []), _d = overEmit.b, { z } = _d, c = __rest(_d, ["z"]), rest2 = __rest(overEmit, ["a", "b"]);
(_e = overEmit.a, [_f, ...y] = _e, nested2 = __rest(_f, []), _g = overEmit.b, { z } = _g, c = __rest(_g, ["z"]), rest2 = __rest(overEmit, ["a", "b"]), overEmit);
var _a, _e, _f, _g;

View File

@ -0,0 +1,59 @@
=== tests/cases/conformance/types/rest/objectRestAssignment.ts ===
let ka: any;
>ka : Symbol(ka, Decl(objectRestAssignment.ts, 0, 3))
let nested: { ki };
>nested : Symbol(nested, Decl(objectRestAssignment.ts, 1, 3))
>ki : Symbol(ki, Decl(objectRestAssignment.ts, 1, 13))
let other: number;
>other : Symbol(other, Decl(objectRestAssignment.ts, 2, 3))
let rest: { };
>rest : Symbol(rest, Decl(objectRestAssignment.ts, 3, 3))
let complex: { x: { ka, ki }, y: number };
>complex : Symbol(complex, Decl(objectRestAssignment.ts, 4, 3))
>x : Symbol(x, Decl(objectRestAssignment.ts, 4, 14))
>ka : Symbol(ka, Decl(objectRestAssignment.ts, 4, 19))
>ki : Symbol(ki, Decl(objectRestAssignment.ts, 4, 23))
>y : Symbol(y, Decl(objectRestAssignment.ts, 4, 29))
({x: { ka, ...nested }, y: other, ...rest} = complex);
>x : Symbol(x, Decl(objectRestAssignment.ts, 5, 2))
>ka : Symbol(ka, Decl(objectRestAssignment.ts, 5, 6))
>y : Symbol(y, Decl(objectRestAssignment.ts, 5, 23))
>other : Symbol(other, Decl(objectRestAssignment.ts, 2, 3))
>complex : Symbol(complex, Decl(objectRestAssignment.ts, 4, 3))
// should be:
let overEmit: { a: { ka: string, x: string }[], b: { z: string, ki: string, ku: string }, ke: string, ko: string };
>overEmit : Symbol(overEmit, Decl(objectRestAssignment.ts, 8, 3))
>a : Symbol(a, Decl(objectRestAssignment.ts, 8, 15))
>ka : Symbol(ka, Decl(objectRestAssignment.ts, 8, 20))
>x : Symbol(x, Decl(objectRestAssignment.ts, 8, 32))
>b : Symbol(b, Decl(objectRestAssignment.ts, 8, 47))
>z : Symbol(z, Decl(objectRestAssignment.ts, 8, 52))
>ki : Symbol(ki, Decl(objectRestAssignment.ts, 8, 63))
>ku : Symbol(ku, Decl(objectRestAssignment.ts, 8, 75))
>ke : Symbol(ke, Decl(objectRestAssignment.ts, 8, 89))
>ko : Symbol(ko, Decl(objectRestAssignment.ts, 8, 101))
// var _g = overEmit.a, [_h, ...y] = _g, nested2 = __rest(_h, []), _j = overEmit.b, { z } = _j, c = __rest(_j, ["z"]), rest2 = __rest(overEmit, ["a", "b"]);
var { a: [{ ...nested2 }, ...y], b: { z, ...c }, ...rest2 } = overEmit;
>a : Symbol(a, Decl(objectRestAssignment.ts, 8, 15))
>nested2 : Symbol(nested2, Decl(objectRestAssignment.ts, 11, 11))
>y : Symbol(y, Decl(objectRestAssignment.ts, 11, 25))
>b : Symbol(b, Decl(objectRestAssignment.ts, 8, 47))
>z : Symbol(z, Decl(objectRestAssignment.ts, 11, 37))
>c : Symbol(c, Decl(objectRestAssignment.ts, 11, 40))
>rest2 : Symbol(rest2, Decl(objectRestAssignment.ts, 11, 48))
>overEmit : Symbol(overEmit, Decl(objectRestAssignment.ts, 8, 3))
({ a: [{ ...nested2 }, ...y], b: { z, ...c }, ...rest2 } = overEmit);
>a : Symbol(a, Decl(objectRestAssignment.ts, 12, 2))
>y : Symbol(y, Decl(objectRestAssignment.ts, 11, 25))
>b : Symbol(b, Decl(objectRestAssignment.ts, 12, 29))
>z : Symbol(z, Decl(objectRestAssignment.ts, 12, 34))
>overEmit : Symbol(overEmit, Decl(objectRestAssignment.ts, 8, 3))

View File

@ -0,0 +1,75 @@
=== tests/cases/conformance/types/rest/objectRestAssignment.ts ===
let ka: any;
>ka : any
let nested: { ki };
>nested : { ki: any; }
>ki : any
let other: number;
>other : number
let rest: { };
>rest : {}
let complex: { x: { ka, ki }, y: number };
>complex : { x: { ka: any; ki: any; }; y: number; }
>x : { ka: any; ki: any; }
>ka : any
>ki : any
>y : number
({x: { ka, ...nested }, y: other, ...rest} = complex);
>({x: { ka, ...nested }, y: other, ...rest} = complex) : { x: { ka: any; ki: any; }; y: number; }
>{x: { ka, ...nested }, y: other, ...rest} = complex : { x: { ka: any; ki: any; }; y: number; }
>{x: { ka, ...nested }, y: other, ...rest} : { x: { ki: any; ka: any; }; y: number; }
>x : { ki: any; ka: any; }
>{ ka, ...nested } : { ki: any; ka: any; }
>ka : any
>nested : any
>y : number
>other : number
>rest : any
>complex : { x: { ka: any; ki: any; }; y: number; }
// should be:
let overEmit: { a: { ka: string, x: string }[], b: { z: string, ki: string, ku: string }, ke: string, ko: string };
>overEmit : { a: { ka: string; x: string; }[]; b: { z: string; ki: string; ku: string; }; ke: string; ko: string; }
>a : { ka: string; x: string; }[]
>ka : string
>x : string
>b : { z: string; ki: string; ku: string; }
>z : string
>ki : string
>ku : string
>ke : string
>ko : string
// var _g = overEmit.a, [_h, ...y] = _g, nested2 = __rest(_h, []), _j = overEmit.b, { z } = _j, c = __rest(_j, ["z"]), rest2 = __rest(overEmit, ["a", "b"]);
var { a: [{ ...nested2 }, ...y], b: { z, ...c }, ...rest2 } = overEmit;
>a : any
>nested2 : { ka: string; x: string; }
>y : { ka: string; x: string; }[]
>b : any
>z : string
>c : { ki: string; ku: string; }
>rest2 : { ke: string; ko: string; }
>overEmit : { a: { ka: string; x: string; }[]; b: { z: string; ki: string; ku: string; }; ke: string; ko: string; }
({ a: [{ ...nested2 }, ...y], b: { z, ...c }, ...rest2 } = overEmit);
>({ a: [{ ...nested2 }, ...y], b: { z, ...c }, ...rest2 } = overEmit) : { a: { ka: string; x: string; }[]; b: { z: string; ki: string; ku: string; }; ke: string; ko: string; }
>{ a: [{ ...nested2 }, ...y], b: { z, ...c }, ...rest2 } = overEmit : { a: { ka: string; x: string; }[]; b: { z: string; ki: string; ku: string; }; ke: string; ko: string; }
>{ a: [{ ...nested2 }, ...y], b: { z, ...c }, ...rest2 } : { ke: string; ko: string; a: { ka: string; x: string; }[]; b: { ki: string; ku: string; z: string; }; }
>a : { ka: string; x: string; }[]
>[{ ...nested2 }, ...y] : { ka: string; x: string; }[]
>{ ...nested2 } : { ka: string; x: string; }
>nested2 : any
>...y : { ka: string; x: string; }
>y : { ka: string; x: string; }[]
>b : { ki: string; ku: string; z: string; }
>{ z, ...c } : { ki: string; ku: string; z: string; }
>z : string
>c : any
>rest2 : any
>overEmit : { a: { ka: string; x: string; }[]; b: { z: string; ki: string; ku: string; }; ke: string; ko: string; }

View File

@ -0,0 +1,45 @@
//// [objectRestForOf.ts]
let array: { x: number, y: string }[];
for (let { x, ...restOf } of array) {
[x, restOf];
}
let xx: number;
let rrestOff: { y: string };
for ({ x: xx, ...rrestOff } of array ) {
[xx, rrestOff];
}
for (const norest of array.map(a => ({ ...a, x: 'a string' }))) {
[norest.x, norest.y];
// x is now a string. who knows why.
}
//// [objectRestForOf.js]
var __assign = (this && this.__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;
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && !e.indexOf(p))
t[p] = s[p];
return t;
};
let array;
for (var array_1 of array) {
var { x } = array_1, restOf = __rest(array_1, ["x"]);
[x, restOf];
}
let xx;
let rrestOff;
for (var array_2 of array) {
({ x: xx } = array_2, rrestOff = __rest(array_2, ["x"]));
[xx, rrestOff];
}
for (const norest of array.map(a => (__assign({}, a, { x: 'a string' })))) {
[norest.x, norest.y];
}

View File

@ -0,0 +1,50 @@
=== tests/cases/conformance/types/rest/objectRestForOf.ts ===
let array: { x: number, y: string }[];
>array : Symbol(array, Decl(objectRestForOf.ts, 0, 3))
>x : Symbol(x, Decl(objectRestForOf.ts, 0, 12))
>y : Symbol(y, Decl(objectRestForOf.ts, 0, 23))
for (let { x, ...restOf } of array) {
>x : Symbol(x, Decl(objectRestForOf.ts, 1, 10))
>restOf : Symbol(restOf, Decl(objectRestForOf.ts, 1, 13))
>array : Symbol(array, Decl(objectRestForOf.ts, 0, 3))
[x, restOf];
>x : Symbol(x, Decl(objectRestForOf.ts, 1, 10))
>restOf : Symbol(restOf, Decl(objectRestForOf.ts, 1, 13))
}
let xx: number;
>xx : Symbol(xx, Decl(objectRestForOf.ts, 4, 3))
let rrestOff: { y: string };
>rrestOff : Symbol(rrestOff, Decl(objectRestForOf.ts, 5, 3))
>y : Symbol(y, Decl(objectRestForOf.ts, 5, 15))
for ({ x: xx, ...rrestOff } of array ) {
>x : Symbol(x, Decl(objectRestForOf.ts, 6, 6))
>xx : Symbol(xx, Decl(objectRestForOf.ts, 4, 3))
>array : Symbol(array, Decl(objectRestForOf.ts, 0, 3))
[xx, rrestOff];
>xx : Symbol(xx, Decl(objectRestForOf.ts, 4, 3))
>rrestOff : Symbol(rrestOff, Decl(objectRestForOf.ts, 5, 3))
}
for (const norest of array.map(a => ({ ...a, x: 'a string' }))) {
>norest : Symbol(norest, Decl(objectRestForOf.ts, 9, 10))
>array.map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>array : Symbol(array, Decl(objectRestForOf.ts, 0, 3))
>map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>a : Symbol(a, Decl(objectRestForOf.ts, 9, 31))
>x : Symbol(x, Decl(objectRestForOf.ts, 9, 44))
[norest.x, norest.y];
>norest.x : Symbol(x, Decl(objectRestForOf.ts, 9, 44))
>norest : Symbol(norest, Decl(objectRestForOf.ts, 9, 10))
>x : Symbol(x, Decl(objectRestForOf.ts, 9, 44))
>norest.y : Symbol(y, Decl(objectRestForOf.ts, 0, 23))
>norest : Symbol(norest, Decl(objectRestForOf.ts, 9, 10))
>y : Symbol(y, Decl(objectRestForOf.ts, 0, 23))
// x is now a string. who knows why.
}

View File

@ -0,0 +1,61 @@
=== tests/cases/conformance/types/rest/objectRestForOf.ts ===
let array: { x: number, y: string }[];
>array : { x: number; y: string; }[]
>x : number
>y : string
for (let { x, ...restOf } of array) {
>x : number
>restOf : { y: string; }
>array : { x: number; y: string; }[]
[x, restOf];
>[x, restOf] : (number | { y: string; })[]
>x : number
>restOf : { y: string; }
}
let xx: number;
>xx : number
let rrestOff: { y: string };
>rrestOff : { y: string; }
>y : string
for ({ x: xx, ...rrestOff } of array ) {
>{ x: xx, ...rrestOff } : { y: string; x: number; }
>x : { x: number; y: string; }
>xx : number
>rrestOff : any
>array : { x: number; y: string; }[]
[xx, rrestOff];
>[xx, rrestOff] : (number | { y: string; })[]
>xx : number
>rrestOff : { y: string; }
}
for (const norest of array.map(a => ({ ...a, x: 'a string' }))) {
>norest : { x: string; y: string; }
>array.map(a => ({ ...a, x: 'a string' })) : { x: string; y: string; }[]
>array.map : { <U>(this: [{ x: number; y: string; }, { x: number; y: string; }, { x: number; y: string; }, { x: number; y: string; }, { x: number; y: string; }], callbackfn: (value: { x: number; y: string; }, index: number, array: { x: number; y: string; }[]) => U, thisArg?: any): [U, U, U, U, U]; <U>(this: [{ x: number; y: string; }, { x: number; y: string; }, { x: number; y: string; }, { x: number; y: string; }], callbackfn: (value: { x: number; y: string; }, index: number, array: { x: number; y: string; }[]) => U, thisArg?: any): [U, U, U, U]; <U>(this: [{ x: number; y: string; }, { x: number; y: string; }, { x: number; y: string; }], callbackfn: (value: { x: number; y: string; }, index: number, array: { x: number; y: string; }[]) => U, thisArg?: any): [U, U, U]; <U>(this: [{ x: number; y: string; }, { x: number; y: string; }], callbackfn: (value: { x: number; y: string; }, index: number, array: { x: number; y: string; }[]) => U, thisArg?: any): [U, U]; <U>(callbackfn: (value: { x: number; y: string; }, index: number, array: { x: number; y: string; }[]) => U, thisArg?: any): U[]; }
>array : { x: number; y: string; }[]
>map : { <U>(this: [{ x: number; y: string; }, { x: number; y: string; }, { x: number; y: string; }, { x: number; y: string; }, { x: number; y: string; }], callbackfn: (value: { x: number; y: string; }, index: number, array: { x: number; y: string; }[]) => U, thisArg?: any): [U, U, U, U, U]; <U>(this: [{ x: number; y: string; }, { x: number; y: string; }, { x: number; y: string; }, { x: number; y: string; }], callbackfn: (value: { x: number; y: string; }, index: number, array: { x: number; y: string; }[]) => U, thisArg?: any): [U, U, U, U]; <U>(this: [{ x: number; y: string; }, { x: number; y: string; }, { x: number; y: string; }], callbackfn: (value: { x: number; y: string; }, index: number, array: { x: number; y: string; }[]) => U, thisArg?: any): [U, U, U]; <U>(this: [{ x: number; y: string; }, { x: number; y: string; }], callbackfn: (value: { x: number; y: string; }, index: number, array: { x: number; y: string; }[]) => U, thisArg?: any): [U, U]; <U>(callbackfn: (value: { x: number; y: string; }, index: number, array: { x: number; y: string; }[]) => U, thisArg?: any): U[]; }
>a => ({ ...a, x: 'a string' }) : (a: { x: number; y: string; }) => { x: string; y: string; }
>a : { x: number; y: string; }
>({ ...a, x: 'a string' }) : { x: string; y: string; }
>{ ...a, x: 'a string' } : { x: string; y: string; }
>a : any
>x : string
>'a string' : "a string"
[norest.x, norest.y];
>[norest.x, norest.y] : string[]
>norest.x : string
>norest : { x: string; y: string; }
>x : string
>norest.y : string
>norest : { x: string; y: string; }
>y : string
// x is now a string. who knows why.
}

View File

@ -0,0 +1,21 @@
tests/cases/conformance/types/rest/objectRestNegative.ts(2,10): error TS2462: A rest element must be last in a destructuring pattern
tests/cases/conformance/types/rest/objectRestNegative.ts(3,31): error TS2462: A rest element must be last in a destructuring pattern
tests/cases/conformance/types/rest/objectRestNegative.ts(6,17): error TS2700: Rest types may only be created from object types.
==== tests/cases/conformance/types/rest/objectRestNegative.ts (3 errors) ====
let o = { a: 1, b: 'no' };
var { ...mustBeLast, a } = o;
~~~~~~~~~~
!!! error TS2462: A rest element must be last in a destructuring pattern
function stillMustBeLast({ ...mustBeLast, a }: { a: number, b: string }): void {
~~~~~~~~~~
!!! error TS2462: A rest element must be last in a destructuring pattern
}
function generic<T extends { x, y }>(t: T) {
let { x, ...rest } = t;
~~~~
!!! error TS2700: Rest types may only be created from object types.
return rest;
}

View File

@ -0,0 +1,27 @@
//// [objectRestNegative.ts]
let o = { a: 1, b: 'no' };
var { ...mustBeLast, a } = o;
function stillMustBeLast({ ...mustBeLast, a }: { a: number, b: string }): void {
}
function generic<T extends { x, y }>(t: T) {
let { x, ...rest } = t;
return rest;
}
//// [objectRestNegative.js]
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && !e.indexOf(p))
t[p] = s[p];
return t;
};
var o = { a: 1, b: 'no' };
var mustBeLast = o.mustBeLast, a = o.a;
function stillMustBeLast(_a) {
var mustBeLast = _a.mustBeLast, a = _a.a;
}
function generic(t) {
var x = t.x, rest = __rest(t, ["x"]);
return rest;
}

View File

@ -0,0 +1,28 @@
//// [objectRestParameter.ts]
function cloneAgain({ a, ...clone }: { a: number, b: string }): void {
}
declare function suddenly(f: (a: { x: { z, ka }, y: string }) => void);
suddenly(({ x: a, ...rest }) => rest.y);
suddenly(({ x: { z = 12, ...nested }, ...rest } = { x: { z: 1, ka: 1 }, y: 'noo' }) => rest.y + nested.ka);
//// [objectRestParameter.js]
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && !e.indexOf(p))
t[p] = s[p];
return t;
};
function cloneAgain(_a) {
var { a } = _a, clone = __rest(_a, ["a"]);
}
suddenly((_a) => {
var { x: a } = _a, rest = __rest(_a, ["x"]);
return rest.y;
});
suddenly((_a = { x: { z: 1, ka: 1 }, y: 'noo' }) => {
var _b = _a.x, { z = 12 } = _b, nested = __rest(_b, ["z"]), rest = __rest(_a, ["x"]);
return rest.y + nested.ka;
});

View File

@ -0,0 +1,45 @@
=== tests/cases/conformance/types/rest/objectRestParameter.ts ===
function cloneAgain({ a, ...clone }: { a: number, b: string }): void {
>cloneAgain : Symbol(cloneAgain, Decl(objectRestParameter.ts, 0, 0))
>a : Symbol(a, Decl(objectRestParameter.ts, 0, 21))
>clone : Symbol(clone, Decl(objectRestParameter.ts, 0, 24))
>a : Symbol(a, Decl(objectRestParameter.ts, 0, 38))
>b : Symbol(b, Decl(objectRestParameter.ts, 0, 49))
}
declare function suddenly(f: (a: { x: { z, ka }, y: string }) => void);
>suddenly : Symbol(suddenly, Decl(objectRestParameter.ts, 1, 1))
>f : Symbol(f, Decl(objectRestParameter.ts, 3, 26))
>a : Symbol(a, Decl(objectRestParameter.ts, 3, 30))
>x : Symbol(x, Decl(objectRestParameter.ts, 3, 34))
>z : Symbol(z, Decl(objectRestParameter.ts, 3, 39))
>ka : Symbol(ka, Decl(objectRestParameter.ts, 3, 42))
>y : Symbol(y, Decl(objectRestParameter.ts, 3, 48))
suddenly(({ x: a, ...rest }) => rest.y);
>suddenly : Symbol(suddenly, Decl(objectRestParameter.ts, 1, 1))
>x : Symbol(x, Decl(objectRestParameter.ts, 3, 34))
>a : Symbol(a, Decl(objectRestParameter.ts, 4, 11))
>rest : Symbol(rest, Decl(objectRestParameter.ts, 4, 17))
>rest.y : Symbol(y, Decl(objectRestParameter.ts, 3, 48))
>rest : Symbol(rest, Decl(objectRestParameter.ts, 4, 17))
>y : Symbol(y, Decl(objectRestParameter.ts, 3, 48))
suddenly(({ x: { z = 12, ...nested }, ...rest } = { x: { z: 1, ka: 1 }, y: 'noo' }) => rest.y + nested.ka);
>suddenly : Symbol(suddenly, Decl(objectRestParameter.ts, 1, 1))
>x : Symbol(x, Decl(objectRestParameter.ts, 3, 34))
>z : Symbol(z, Decl(objectRestParameter.ts, 5, 16))
>nested : Symbol(nested, Decl(objectRestParameter.ts, 5, 24))
>rest : Symbol(rest, Decl(objectRestParameter.ts, 5, 37))
>x : Symbol(x, Decl(objectRestParameter.ts, 5, 51))
>z : Symbol(z, Decl(objectRestParameter.ts, 5, 56))
>ka : Symbol(ka, Decl(objectRestParameter.ts, 5, 62))
>y : Symbol(y, Decl(objectRestParameter.ts, 5, 71))
>rest.y : Symbol(y, Decl(objectRestParameter.ts, 3, 48))
>rest : Symbol(rest, Decl(objectRestParameter.ts, 5, 37))
>y : Symbol(y, Decl(objectRestParameter.ts, 3, 48))
>nested.ka : Symbol(ka, Decl(objectRestParameter.ts, 3, 42))
>nested : Symbol(nested, Decl(objectRestParameter.ts, 5, 24))
>ka : Symbol(ka, Decl(objectRestParameter.ts, 3, 42))

View File

@ -0,0 +1,56 @@
=== tests/cases/conformance/types/rest/objectRestParameter.ts ===
function cloneAgain({ a, ...clone }: { a: number, b: string }): void {
>cloneAgain : ({a, ...clone}: { a: number; b: string; }) => void
>a : number
>clone : { b: string; }
>a : number
>b : string
}
declare function suddenly(f: (a: { x: { z, ka }, y: string }) => void);
>suddenly : (f: (a: { x: { z: any; ka: any; }; y: string; }) => void) => any
>f : (a: { x: { z: any; ka: any; }; y: string; }) => void
>a : { x: { z: any; ka: any; }; y: string; }
>x : { z: any; ka: any; }
>z : any
>ka : any
>y : string
suddenly(({ x: a, ...rest }) => rest.y);
>suddenly(({ x: a, ...rest }) => rest.y) : any
>suddenly : (f: (a: { x: { z: any; ka: any; }; y: string; }) => void) => any
>({ x: a, ...rest }) => rest.y : ({x: a, ...rest}: { x: { z: any; ka: any; }; y: string; }) => string
>x : any
>a : { z: any; ka: any; }
>rest : { y: string; }
>rest.y : string
>rest : { y: string; }
>y : string
suddenly(({ x: { z = 12, ...nested }, ...rest } = { x: { z: 1, ka: 1 }, y: 'noo' }) => rest.y + nested.ka);
>suddenly(({ x: { z = 12, ...nested }, ...rest } = { x: { z: 1, ka: 1 }, y: 'noo' }) => rest.y + nested.ka) : any
>suddenly : (f: (a: { x: { z: any; ka: any; }; y: string; }) => void) => any
>({ x: { z = 12, ...nested }, ...rest } = { x: { z: 1, ka: 1 }, y: 'noo' }) => rest.y + nested.ka : ({x: {z, ...nested}, ...rest}?: { x: { z: any; ka: any; }; y: string; }) => string
>x : any
>z : any
>12 : 12
>nested : { ka: any; }
>rest : { y: string; }
>{ x: { z: 1, ka: 1 }, y: 'noo' } : { x: { z: number; ka: number; }; y: string; }
>x : { z: number; ka: number; }
>{ z: 1, ka: 1 } : { z: number; ka: number; }
>z : number
>1 : 1
>ka : number
>1 : 1
>y : string
>'noo' : "noo"
>rest.y + nested.ka : string
>rest.y : string
>rest : { y: string; }
>y : string
>nested.ka : any
>nested : { ka: any; }
>ka : any

View File

@ -0,0 +1,151 @@
//// [objectSpread.ts]
let o = { a: 1, b: 'no' }
let o2 = { b: 'yes', c: true }
let swap = { a: 'yes', b: -1 };
let addAfter: { a: number, b: string, c: boolean } =
{ ...o, c: false }
let addBefore: { a: number, b: string, c: boolean } =
{ c: false, ...o }
// Note: ignore still changes the order that properties are printed
let ignore: { a: number, b: string } =
{ b: 'ignored', ...o }
let override: { a: number, b: string } =
{ ...o, b: 'override' }
let nested: { a: number, b: boolean, c: string } =
{ ...{ a: 3, ...{ b: false, c: 'overriden' } }, c: 'whatever' }
let combined: { a: number, b: string, c: boolean } =
{ ...o, ...o2 }
let combinedBefore: { a: number, b: string, c: boolean } =
{ b: 'ok', ...o, ...o2 }
let combinedMid: { a: number, b: string, c: boolean } =
{ ...o, b: 'ok', ...o2 }
let combinedAfter: { a: number, b: string, c: boolean } =
{ ...o, ...o2, b: 'ok' }
let combinedNested: { a: number, b: boolean, c: string, d: string } =
{ ...{ a: 4, ...{ b: false, c: 'overriden' } }, d: 'actually new', ...{ a: 5, d: 'maybe new' } }
let combinedNestedChangeType: { a: number, b: boolean, c: number } =
{ ...{ a: 1, ...{ b: false, c: 'overriden' } }, c: -1 }
let propertyNested: { a: { a: number, b: string } } =
{ a: { ... o } }
// accessors don't copy the descriptor
// (which means that readonly getters become read/write properties)
let op = { get a () { return 6 } };
let getter: { a: number, c: number } =
{ ...op, c: 7 }
getter.a = 12;
// functions result in { }
let spreadFunc = { ...(function () { }) };
// any results in any
let anything: any;
let spreadAny = { ...anything };
// methods are not enumerable
class C { p = 1; m() { } }
let c: C = new C()
let spreadC: { p: number } = { ...c }
// own methods are enumerable
let cplus: { p: number, plus(): void } = { ...c, plus() { return this.p + 1; } };
cplus.plus();
// new field's type conflicting with existing field is OK
let changeTypeAfter: { a: string, b: string } =
{ ...o, a: 'wrong type?' }
let changeTypeBefore: { a: number, b: string } =
{ a: 'wrong type?', ...o };
let changeTypeBoth: { a: string, b: number } =
{ ...o, ...swap };
// optional
let definiteBoolean: { sn: boolean };
let definiteString: { sn: string };
let optionalString: { sn?: string };
let optionalNumber: { sn?: number };
let optionalUnionStops: { sn: string | number | boolean } = { ...definiteBoolean, ...definiteString, ...optionalNumber };
let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber };
let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber };
// computed property
let computedFirst: { a: number, b: string, "before everything": number } =
{ ['before everything']: 12, ...o, b: 'yes' }
let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } =
{ ...o, ['in the middle']: 13, b: 'maybe?', ...o2 }
let computedAfter: { a: number, b: string, "at the end": number } =
{ ...o, b: 'yeah', ['at the end']: 14 }
// shortcut syntax
let a = 12;
let shortCutted: { a: number, b: string } = { ...o, a }
//// [objectSpread.js]
var __assign = (this && this.__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;
};
var o = { a: 1, b: 'no' };
var o2 = { b: 'yes', c: true };
var swap = { a: 'yes', b: -1 };
var addAfter = __assign({}, o, { c: false });
var addBefore = __assign({ c: false }, o);
// Note: ignore still changes the order that properties are printed
var ignore = __assign({ b: 'ignored' }, o);
var override = __assign({}, o, { b: 'override' });
var nested = __assign({}, __assign({ a: 3 }, { b: false, c: 'overriden' }), { c: 'whatever' });
var combined = __assign({}, o, o2);
var combinedBefore = __assign({ b: 'ok' }, o, o2);
var combinedMid = __assign({}, o, { b: 'ok' }, o2);
var combinedAfter = __assign({}, o, o2, { b: 'ok' });
var combinedNested = __assign({}, __assign({ a: 4 }, { b: false, c: 'overriden' }), { d: 'actually new' }, { a: 5, d: 'maybe new' });
var combinedNestedChangeType = __assign({}, __assign({ a: 1 }, { b: false, c: 'overriden' }), { c: -1 });
var propertyNested = __assign({ a: __assign({}, o) });
// accessors don't copy the descriptor
// (which means that readonly getters become read/write properties)
var op = { get a() { return 6; } };
var getter = __assign({}, op, { c: 7 });
getter.a = 12;
// functions result in { }
var spreadFunc = __assign({}, (function () { }));
// any results in any
var anything;
var spreadAny = __assign({}, anything);
// methods are not enumerable
var C = (function () {
function C() {
this.p = 1;
}
C.prototype.m = function () { };
return C;
}());
var c = new C();
var spreadC = __assign({}, c);
// own methods are enumerable
var cplus = __assign({}, c, { plus: function () { return this.p + 1; } });
cplus.plus();
// new field's type conflicting with existing field is OK
var changeTypeAfter = __assign({}, o, { a: 'wrong type?' });
var changeTypeBefore = __assign({ a: 'wrong type?' }, o);
var changeTypeBoth = __assign({}, o, swap);
// optional
var definiteBoolean;
var definiteString;
var optionalString;
var optionalNumber;
var optionalUnionStops = __assign({}, definiteBoolean, definiteString, optionalNumber);
var optionalUnionDuplicates = __assign({}, definiteBoolean, definiteString, optionalString, optionalNumber);
var allOptional = __assign({}, optionalString, optionalNumber);
// computed property
var computedFirst = __assign((_a = {}, _a['before everything'] = 12, _a), o, { b: 'yes' });
var computedMiddle = __assign({}, o, (_b = {}, _b['in the middle'] = 13, _b.b = 'maybe?', _b), o2);
var computedAfter = __assign({}, o, (_c = { b: 'yeah' }, _c['at the end'] = 14, _c));
// shortcut syntax
var a = 12;
var shortCutted = __assign({}, o, { a: a });
var _a, _b, _c;

View File

@ -0,0 +1,284 @@
=== tests/cases/conformance/types/spread/objectSpread.ts ===
let o = { a: 1, b: 'no' }
>o : Symbol(o, Decl(objectSpread.ts, 0, 3))
>a : Symbol(a, Decl(objectSpread.ts, 0, 9))
>b : Symbol(b, Decl(objectSpread.ts, 0, 15))
let o2 = { b: 'yes', c: true }
>o2 : Symbol(o2, Decl(objectSpread.ts, 1, 3))
>b : Symbol(b, Decl(objectSpread.ts, 1, 10))
>c : Symbol(c, Decl(objectSpread.ts, 1, 20))
let swap = { a: 'yes', b: -1 };
>swap : Symbol(swap, Decl(objectSpread.ts, 2, 3))
>a : Symbol(a, Decl(objectSpread.ts, 2, 12))
>b : Symbol(b, Decl(objectSpread.ts, 2, 22))
let addAfter: { a: number, b: string, c: boolean } =
>addAfter : Symbol(addAfter, Decl(objectSpread.ts, 4, 3))
>a : Symbol(a, Decl(objectSpread.ts, 4, 15))
>b : Symbol(b, Decl(objectSpread.ts, 4, 26))
>c : Symbol(c, Decl(objectSpread.ts, 4, 37))
{ ...o, c: false }
>c : Symbol(c, Decl(objectSpread.ts, 5, 11))
let addBefore: { a: number, b: string, c: boolean } =
>addBefore : Symbol(addBefore, Decl(objectSpread.ts, 6, 3))
>a : Symbol(a, Decl(objectSpread.ts, 6, 16))
>b : Symbol(b, Decl(objectSpread.ts, 6, 27))
>c : Symbol(c, Decl(objectSpread.ts, 6, 38))
{ c: false, ...o }
>c : Symbol(c, Decl(objectSpread.ts, 7, 5))
// Note: ignore still changes the order that properties are printed
let ignore: { a: number, b: string } =
>ignore : Symbol(ignore, Decl(objectSpread.ts, 9, 3))
>a : Symbol(a, Decl(objectSpread.ts, 9, 13))
>b : Symbol(b, Decl(objectSpread.ts, 9, 24))
{ b: 'ignored', ...o }
>b : Symbol(b, Decl(objectSpread.ts, 10, 5))
let override: { a: number, b: string } =
>override : Symbol(override, Decl(objectSpread.ts, 11, 3))
>a : Symbol(a, Decl(objectSpread.ts, 11, 15))
>b : Symbol(b, Decl(objectSpread.ts, 11, 26))
{ ...o, b: 'override' }
>b : Symbol(b, Decl(objectSpread.ts, 12, 11))
let nested: { a: number, b: boolean, c: string } =
>nested : Symbol(nested, Decl(objectSpread.ts, 13, 3))
>a : Symbol(a, Decl(objectSpread.ts, 13, 13))
>b : Symbol(b, Decl(objectSpread.ts, 13, 24))
>c : Symbol(c, Decl(objectSpread.ts, 13, 36))
{ ...{ a: 3, ...{ b: false, c: 'overriden' } }, c: 'whatever' }
>a : Symbol(a, Decl(objectSpread.ts, 14, 10))
>b : Symbol(b, Decl(objectSpread.ts, 14, 21))
>c : Symbol(c, Decl(objectSpread.ts, 14, 31))
>c : Symbol(c, Decl(objectSpread.ts, 14, 51))
let combined: { a: number, b: string, c: boolean } =
>combined : Symbol(combined, Decl(objectSpread.ts, 15, 3))
>a : Symbol(a, Decl(objectSpread.ts, 15, 15))
>b : Symbol(b, Decl(objectSpread.ts, 15, 26))
>c : Symbol(c, Decl(objectSpread.ts, 15, 37))
{ ...o, ...o2 }
let combinedBefore: { a: number, b: string, c: boolean } =
>combinedBefore : Symbol(combinedBefore, Decl(objectSpread.ts, 17, 3))
>a : Symbol(a, Decl(objectSpread.ts, 17, 21))
>b : Symbol(b, Decl(objectSpread.ts, 17, 32))
>c : Symbol(c, Decl(objectSpread.ts, 17, 43))
{ b: 'ok', ...o, ...o2 }
>b : Symbol(b, Decl(objectSpread.ts, 18, 5))
let combinedMid: { a: number, b: string, c: boolean } =
>combinedMid : Symbol(combinedMid, Decl(objectSpread.ts, 19, 3))
>a : Symbol(a, Decl(objectSpread.ts, 19, 18))
>b : Symbol(b, Decl(objectSpread.ts, 19, 29))
>c : Symbol(c, Decl(objectSpread.ts, 19, 40))
{ ...o, b: 'ok', ...o2 }
>b : Symbol(b, Decl(objectSpread.ts, 20, 11))
let combinedAfter: { a: number, b: string, c: boolean } =
>combinedAfter : Symbol(combinedAfter, Decl(objectSpread.ts, 21, 3))
>a : Symbol(a, Decl(objectSpread.ts, 21, 20))
>b : Symbol(b, Decl(objectSpread.ts, 21, 31))
>c : Symbol(c, Decl(objectSpread.ts, 21, 42))
{ ...o, ...o2, b: 'ok' }
>b : Symbol(b, Decl(objectSpread.ts, 22, 18))
let combinedNested: { a: number, b: boolean, c: string, d: string } =
>combinedNested : Symbol(combinedNested, Decl(objectSpread.ts, 23, 3))
>a : Symbol(a, Decl(objectSpread.ts, 23, 21))
>b : Symbol(b, Decl(objectSpread.ts, 23, 32))
>c : Symbol(c, Decl(objectSpread.ts, 23, 44))
>d : Symbol(d, Decl(objectSpread.ts, 23, 55))
{ ...{ a: 4, ...{ b: false, c: 'overriden' } }, d: 'actually new', ...{ a: 5, d: 'maybe new' } }
>a : Symbol(a, Decl(objectSpread.ts, 24, 10))
>b : Symbol(b, Decl(objectSpread.ts, 24, 21))
>c : Symbol(c, Decl(objectSpread.ts, 24, 31))
>d : Symbol(d, Decl(objectSpread.ts, 24, 51))
>a : Symbol(a, Decl(objectSpread.ts, 24, 75))
>d : Symbol(d, Decl(objectSpread.ts, 24, 81))
let combinedNestedChangeType: { a: number, b: boolean, c: number } =
>combinedNestedChangeType : Symbol(combinedNestedChangeType, Decl(objectSpread.ts, 25, 3))
>a : Symbol(a, Decl(objectSpread.ts, 25, 31))
>b : Symbol(b, Decl(objectSpread.ts, 25, 42))
>c : Symbol(c, Decl(objectSpread.ts, 25, 54))
{ ...{ a: 1, ...{ b: false, c: 'overriden' } }, c: -1 }
>a : Symbol(a, Decl(objectSpread.ts, 26, 10))
>b : Symbol(b, Decl(objectSpread.ts, 26, 21))
>c : Symbol(c, Decl(objectSpread.ts, 26, 31))
>c : Symbol(c, Decl(objectSpread.ts, 26, 51))
let propertyNested: { a: { a: number, b: string } } =
>propertyNested : Symbol(propertyNested, Decl(objectSpread.ts, 27, 3))
>a : Symbol(a, Decl(objectSpread.ts, 27, 21))
>a : Symbol(a, Decl(objectSpread.ts, 27, 26))
>b : Symbol(b, Decl(objectSpread.ts, 27, 37))
{ a: { ... o } }
>a : Symbol(a, Decl(objectSpread.ts, 28, 5))
// accessors don't copy the descriptor
// (which means that readonly getters become read/write properties)
let op = { get a () { return 6 } };
>op : Symbol(op, Decl(objectSpread.ts, 31, 3))
>a : Symbol(a, Decl(objectSpread.ts, 31, 10))
let getter: { a: number, c: number } =
>getter : Symbol(getter, Decl(objectSpread.ts, 32, 3))
>a : Symbol(a, Decl(objectSpread.ts, 32, 13))
>c : Symbol(c, Decl(objectSpread.ts, 32, 24))
{ ...op, c: 7 }
>c : Symbol(c, Decl(objectSpread.ts, 33, 12))
getter.a = 12;
>getter.a : Symbol(a, Decl(objectSpread.ts, 32, 13))
>getter : Symbol(getter, Decl(objectSpread.ts, 32, 3))
>a : Symbol(a, Decl(objectSpread.ts, 32, 13))
// functions result in { }
let spreadFunc = { ...(function () { }) };
>spreadFunc : Symbol(spreadFunc, Decl(objectSpread.ts, 37, 3))
// any results in any
let anything: any;
>anything : Symbol(anything, Decl(objectSpread.ts, 40, 3))
let spreadAny = { ...anything };
>spreadAny : Symbol(spreadAny, Decl(objectSpread.ts, 41, 3))
// methods are not enumerable
class C { p = 1; m() { } }
>C : Symbol(C, Decl(objectSpread.ts, 41, 32))
>p : Symbol(C.p, Decl(objectSpread.ts, 44, 9))
>m : Symbol(C.m, Decl(objectSpread.ts, 44, 16))
let c: C = new C()
>c : Symbol(c, Decl(objectSpread.ts, 45, 3))
>C : Symbol(C, Decl(objectSpread.ts, 41, 32))
>C : Symbol(C, Decl(objectSpread.ts, 41, 32))
let spreadC: { p: number } = { ...c }
>spreadC : Symbol(spreadC, Decl(objectSpread.ts, 46, 3))
>p : Symbol(p, Decl(objectSpread.ts, 46, 14))
// own methods are enumerable
let cplus: { p: number, plus(): void } = { ...c, plus() { return this.p + 1; } };
>cplus : Symbol(cplus, Decl(objectSpread.ts, 49, 3))
>p : Symbol(p, Decl(objectSpread.ts, 49, 12))
>plus : Symbol(plus, Decl(objectSpread.ts, 49, 23))
>plus : Symbol(plus, Decl(objectSpread.ts, 49, 48))
>this : Symbol(__object, Decl(objectSpread.ts, 41, 15))
cplus.plus();
>cplus.plus : Symbol(plus, Decl(objectSpread.ts, 49, 23))
>cplus : Symbol(cplus, Decl(objectSpread.ts, 49, 3))
>plus : Symbol(plus, Decl(objectSpread.ts, 49, 23))
// new field's type conflicting with existing field is OK
let changeTypeAfter: { a: string, b: string } =
>changeTypeAfter : Symbol(changeTypeAfter, Decl(objectSpread.ts, 53, 3))
>a : Symbol(a, Decl(objectSpread.ts, 53, 22))
>b : Symbol(b, Decl(objectSpread.ts, 53, 33))
{ ...o, a: 'wrong type?' }
>a : Symbol(a, Decl(objectSpread.ts, 54, 11))
let changeTypeBefore: { a: number, b: string } =
>changeTypeBefore : Symbol(changeTypeBefore, Decl(objectSpread.ts, 55, 3))
>a : Symbol(a, Decl(objectSpread.ts, 55, 23))
>b : Symbol(b, Decl(objectSpread.ts, 55, 34))
{ a: 'wrong type?', ...o };
>a : Symbol(a, Decl(objectSpread.ts, 56, 5))
let changeTypeBoth: { a: string, b: number } =
>changeTypeBoth : Symbol(changeTypeBoth, Decl(objectSpread.ts, 57, 3))
>a : Symbol(a, Decl(objectSpread.ts, 57, 21))
>b : Symbol(b, Decl(objectSpread.ts, 57, 32))
{ ...o, ...swap };
// optional
let definiteBoolean: { sn: boolean };
>definiteBoolean : Symbol(definiteBoolean, Decl(objectSpread.ts, 61, 3))
>sn : Symbol(sn, Decl(objectSpread.ts, 61, 22))
let definiteString: { sn: string };
>definiteString : Symbol(definiteString, Decl(objectSpread.ts, 62, 3))
>sn : Symbol(sn, Decl(objectSpread.ts, 62, 21))
let optionalString: { sn?: string };
>optionalString : Symbol(optionalString, Decl(objectSpread.ts, 63, 3))
>sn : Symbol(sn, Decl(objectSpread.ts, 63, 21))
let optionalNumber: { sn?: number };
>optionalNumber : Symbol(optionalNumber, Decl(objectSpread.ts, 64, 3))
>sn : Symbol(sn, Decl(objectSpread.ts, 64, 21))
let optionalUnionStops: { sn: string | number | boolean } = { ...definiteBoolean, ...definiteString, ...optionalNumber };
>optionalUnionStops : Symbol(optionalUnionStops, Decl(objectSpread.ts, 65, 3))
>sn : Symbol(sn, Decl(objectSpread.ts, 65, 25))
let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber };
>optionalUnionDuplicates : Symbol(optionalUnionDuplicates, Decl(objectSpread.ts, 66, 3))
>sn : Symbol(sn, Decl(objectSpread.ts, 66, 30))
let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber };
>allOptional : Symbol(allOptional, Decl(objectSpread.ts, 67, 3))
>sn : Symbol(sn, Decl(objectSpread.ts, 67, 18))
// computed property
let computedFirst: { a: number, b: string, "before everything": number } =
>computedFirst : Symbol(computedFirst, Decl(objectSpread.ts, 70, 3))
>a : Symbol(a, Decl(objectSpread.ts, 70, 20))
>b : Symbol(b, Decl(objectSpread.ts, 70, 31))
{ ['before everything']: 12, ...o, b: 'yes' }
>'before everything' : Symbol(['before everything'], Decl(objectSpread.ts, 71, 5))
>b : Symbol(b, Decl(objectSpread.ts, 71, 38))
let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } =
>computedMiddle : Symbol(computedMiddle, Decl(objectSpread.ts, 72, 3))
>a : Symbol(a, Decl(objectSpread.ts, 72, 21))
>b : Symbol(b, Decl(objectSpread.ts, 72, 32))
>c : Symbol(c, Decl(objectSpread.ts, 72, 43))
{ ...o, ['in the middle']: 13, b: 'maybe?', ...o2 }
>'in the middle' : Symbol(['in the middle'], Decl(objectSpread.ts, 73, 11))
>b : Symbol(b, Decl(objectSpread.ts, 73, 34))
let computedAfter: { a: number, b: string, "at the end": number } =
>computedAfter : Symbol(computedAfter, Decl(objectSpread.ts, 74, 3))
>a : Symbol(a, Decl(objectSpread.ts, 74, 20))
>b : Symbol(b, Decl(objectSpread.ts, 74, 31))
{ ...o, b: 'yeah', ['at the end']: 14 }
>b : Symbol(b, Decl(objectSpread.ts, 75, 11))
>'at the end' : Symbol(['at the end'], Decl(objectSpread.ts, 75, 22))
// shortcut syntax
let a = 12;
>a : Symbol(a, Decl(objectSpread.ts, 77, 3))
let shortCutted: { a: number, b: string } = { ...o, a }
>shortCutted : Symbol(shortCutted, Decl(objectSpread.ts, 78, 3))
>a : Symbol(a, Decl(objectSpread.ts, 78, 18))
>b : Symbol(b, Decl(objectSpread.ts, 78, 29))
>a : Symbol(a, Decl(objectSpread.ts, 78, 51))

View File

@ -0,0 +1,410 @@
=== tests/cases/conformance/types/spread/objectSpread.ts ===
let o = { a: 1, b: 'no' }
>o : { a: number; b: string; }
>{ a: 1, b: 'no' } : { a: number; b: string; }
>a : number
>1 : 1
>b : string
>'no' : "no"
let o2 = { b: 'yes', c: true }
>o2 : { b: string; c: boolean; }
>{ b: 'yes', c: true } : { b: string; c: boolean; }
>b : string
>'yes' : "yes"
>c : boolean
>true : true
let swap = { a: 'yes', b: -1 };
>swap : { a: string; b: number; }
>{ a: 'yes', b: -1 } : { a: string; b: number; }
>a : string
>'yes' : "yes"
>b : number
>-1 : -1
>1 : 1
let addAfter: { a: number, b: string, c: boolean } =
>addAfter : { a: number; b: string; c: boolean; }
>a : number
>b : string
>c : boolean
{ ...o, c: false }
>{ ...o, c: false } : { c: false; a: number; b: string; }
>o : any
>c : boolean
>false : false
let addBefore: { a: number, b: string, c: boolean } =
>addBefore : { a: number; b: string; c: boolean; }
>a : number
>b : string
>c : boolean
{ c: false, ...o }
>{ c: false, ...o } : { a: number; b: string; c: false; }
>c : boolean
>false : false
>o : any
// Note: ignore still changes the order that properties are printed
let ignore: { a: number, b: string } =
>ignore : { a: number; b: string; }
>a : number
>b : string
{ b: 'ignored', ...o }
>{ b: 'ignored', ...o } : { a: number; b: string; }
>b : string
>'ignored' : "ignored"
>o : any
let override: { a: number, b: string } =
>override : { a: number; b: string; }
>a : number
>b : string
{ ...o, b: 'override' }
>{ ...o, b: 'override' } : { b: string; a: number; }
>o : any
>b : string
>'override' : "override"
let nested: { a: number, b: boolean, c: string } =
>nested : { a: number; b: boolean; c: string; }
>a : number
>b : boolean
>c : string
{ ...{ a: 3, ...{ b: false, c: 'overriden' } }, c: 'whatever' }
>{ ...{ a: 3, ...{ b: false, c: 'overriden' } }, c: 'whatever' } : { c: string; b: boolean; a: number; }
>{ a: 3, ...{ b: false, c: 'overriden' } } : { b: boolean; c: string; a: number; }
>a : number
>3 : 3
>{ b: false, c: 'overriden' } : { b: boolean; c: string; }
>b : boolean
>false : false
>c : string
>'overriden' : "overriden"
>c : string
>'whatever' : "whatever"
let combined: { a: number, b: string, c: boolean } =
>combined : { a: number; b: string; c: boolean; }
>a : number
>b : string
>c : boolean
{ ...o, ...o2 }
>{ ...o, ...o2 } : { b: string; c: boolean; a: number; }
>o : any
>o2 : any
let combinedBefore: { a: number, b: string, c: boolean } =
>combinedBefore : { a: number; b: string; c: boolean; }
>a : number
>b : string
>c : boolean
{ b: 'ok', ...o, ...o2 }
>{ b: 'ok', ...o, ...o2 } : { b: string; c: boolean; a: number; }
>b : string
>'ok' : "ok"
>o : any
>o2 : any
let combinedMid: { a: number, b: string, c: boolean } =
>combinedMid : { a: number; b: string; c: boolean; }
>a : number
>b : string
>c : boolean
{ ...o, b: 'ok', ...o2 }
>{ ...o, b: 'ok', ...o2 } : { b: string; c: boolean; a: number; }
>o : any
>b : string
>'ok' : "ok"
>o2 : any
let combinedAfter: { a: number, b: string, c: boolean } =
>combinedAfter : { a: number; b: string; c: boolean; }
>a : number
>b : string
>c : boolean
{ ...o, ...o2, b: 'ok' }
>{ ...o, ...o2, b: 'ok' } : { b: string; c: boolean; a: number; }
>o : any
>o2 : any
>b : string
>'ok' : "ok"
let combinedNested: { a: number, b: boolean, c: string, d: string } =
>combinedNested : { a: number; b: boolean; c: string; d: string; }
>a : number
>b : boolean
>c : string
>d : string
{ ...{ a: 4, ...{ b: false, c: 'overriden' } }, d: 'actually new', ...{ a: 5, d: 'maybe new' } }
>{ ...{ a: 4, ...{ b: false, c: 'overriden' } }, d: 'actually new', ...{ a: 5, d: 'maybe new' } } : { a: number; d: string; b: boolean; c: string; }
>{ a: 4, ...{ b: false, c: 'overriden' } } : { b: boolean; c: string; a: number; }
>a : number
>4 : 4
>{ b: false, c: 'overriden' } : { b: boolean; c: string; }
>b : boolean
>false : false
>c : string
>'overriden' : "overriden"
>d : string
>'actually new' : "actually new"
>{ a: 5, d: 'maybe new' } : { a: number; d: string; }
>a : number
>5 : 5
>d : string
>'maybe new' : "maybe new"
let combinedNestedChangeType: { a: number, b: boolean, c: number } =
>combinedNestedChangeType : { a: number; b: boolean; c: number; }
>a : number
>b : boolean
>c : number
{ ...{ a: 1, ...{ b: false, c: 'overriden' } }, c: -1 }
>{ ...{ a: 1, ...{ b: false, c: 'overriden' } }, c: -1 } : { c: number; b: boolean; a: number; }
>{ a: 1, ...{ b: false, c: 'overriden' } } : { b: boolean; c: string; a: number; }
>a : number
>1 : 1
>{ b: false, c: 'overriden' } : { b: boolean; c: string; }
>b : boolean
>false : false
>c : string
>'overriden' : "overriden"
>c : number
>-1 : -1
>1 : 1
let propertyNested: { a: { a: number, b: string } } =
>propertyNested : { a: { a: number; b: string; }; }
>a : { a: number; b: string; }
>a : number
>b : string
{ a: { ... o } }
>{ a: { ... o } } : { a: { a: number; b: string; }; }
>a : { a: number; b: string; }
>{ ... o } : { a: number; b: string; }
>o : any
// accessors don't copy the descriptor
// (which means that readonly getters become read/write properties)
let op = { get a () { return 6 } };
>op : { readonly a: number; }
>{ get a () { return 6 } } : { readonly a: number; }
>a : number
>6 : 6
let getter: { a: number, c: number } =
>getter : { a: number; c: number; }
>a : number
>c : number
{ ...op, c: 7 }
>{ ...op, c: 7 } : { c: number; readonly a: number; }
>op : any
>c : number
>7 : 7
getter.a = 12;
>getter.a = 12 : 12
>getter.a : number
>getter : { a: number; c: number; }
>a : number
>12 : 12
// functions result in { }
let spreadFunc = { ...(function () { }) };
>spreadFunc : {}
>{ ...(function () { }) } : {}
>(function () { }) : () => void
>function () { } : () => void
// any results in any
let anything: any;
>anything : any
let spreadAny = { ...anything };
>spreadAny : any
>{ ...anything } : any
>anything : any
// methods are not enumerable
class C { p = 1; m() { } }
>C : C
>p : number
>1 : 1
>m : () => void
let c: C = new C()
>c : C
>C : C
>new C() : C
>C : typeof C
let spreadC: { p: number } = { ...c }
>spreadC : { p: number; }
>p : number
>{ ...c } : { p: number; }
>c : any
// own methods are enumerable
let cplus: { p: number, plus(): void } = { ...c, plus() { return this.p + 1; } };
>cplus : { p: number; plus(): void; }
>p : number
>plus : () => void
>{ ...c, plus() { return this.p + 1; } } : { plus(): any; p: number; }
>c : any
>plus : () => any
>this.p + 1 : any
>this.p : any
>this : any
>p : any
>1 : 1
cplus.plus();
>cplus.plus() : void
>cplus.plus : () => void
>cplus : { p: number; plus(): void; }
>plus : () => void
// new field's type conflicting with existing field is OK
let changeTypeAfter: { a: string, b: string } =
>changeTypeAfter : { a: string; b: string; }
>a : string
>b : string
{ ...o, a: 'wrong type?' }
>{ ...o, a: 'wrong type?' } : { a: string; b: string; }
>o : any
>a : string
>'wrong type?' : "wrong type?"
let changeTypeBefore: { a: number, b: string } =
>changeTypeBefore : { a: number; b: string; }
>a : number
>b : string
{ a: 'wrong type?', ...o };
>{ a: 'wrong type?', ...o } : { a: number; b: string; }
>a : string
>'wrong type?' : "wrong type?"
>o : any
let changeTypeBoth: { a: string, b: number } =
>changeTypeBoth : { a: string; b: number; }
>a : string
>b : number
{ ...o, ...swap };
>{ ...o, ...swap } : { a: string; b: number; }
>o : any
>swap : any
// optional
let definiteBoolean: { sn: boolean };
>definiteBoolean : { sn: boolean; }
>sn : boolean
let definiteString: { sn: string };
>definiteString : { sn: string; }
>sn : string
let optionalString: { sn?: string };
>optionalString : { sn?: string; }
>sn : string
let optionalNumber: { sn?: number };
>optionalNumber : { sn?: number; }
>sn : number
let optionalUnionStops: { sn: string | number | boolean } = { ...definiteBoolean, ...definiteString, ...optionalNumber };
>optionalUnionStops : { sn: string | number | boolean; }
>sn : string | number | boolean
>{ ...definiteBoolean, ...definiteString, ...optionalNumber } : { sn: string | number; }
>definiteBoolean : any
>definiteString : any
>optionalNumber : any
let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber };
>optionalUnionDuplicates : { sn: string | number; }
>sn : string | number
>{ ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber } : { sn: string | number; }
>definiteBoolean : any
>definiteString : any
>optionalString : any
>optionalNumber : any
let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber };
>allOptional : { sn?: string | number; }
>sn : string | number
>{ ...optionalString, ...optionalNumber } : { sn?: string | number; }
>optionalString : any
>optionalNumber : any
// computed property
let computedFirst: { a: number, b: string, "before everything": number } =
>computedFirst : { a: number; b: string; "before everything": number; }
>a : number
>b : string
{ ['before everything']: 12, ...o, b: 'yes' }
>{ ['before everything']: 12, ...o, b: 'yes' } : { b: string; a: number; ['before everything']: number; }
>'before everything' : "before everything"
>12 : 12
>o : any
>b : string
>'yes' : "yes"
let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } =
>computedMiddle : { a: number; b: string; c: boolean; "in the middle": number; }
>a : number
>b : string
>c : boolean
{ ...o, ['in the middle']: 13, b: 'maybe?', ...o2 }
>{ ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } : { b: string; c: boolean; ['in the middle']: number; a: number; }
>o : any
>'in the middle' : "in the middle"
>13 : 13
>b : string
>'maybe?' : "maybe?"
>o2 : any
let computedAfter: { a: number, b: string, "at the end": number } =
>computedAfter : { a: number; b: string; "at the end": number; }
>a : number
>b : string
{ ...o, b: 'yeah', ['at the end']: 14 }
>{ ...o, b: 'yeah', ['at the end']: 14 } : { b: string; ['at the end']: number; a: number; }
>o : any
>b : string
>'yeah' : "yeah"
>'at the end' : "at the end"
>14 : 14
// shortcut syntax
let a = 12;
>a : number
>12 : 12
let shortCutted: { a: number, b: string } = { ...o, a }
>shortCutted : { a: number; b: string; }
>a : number
>b : string
>{ ...o, a } : { a: number; b: string; }
>o : any
>a : number

View File

@ -0,0 +1,36 @@
//// [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 };
// only indexed has indexer, so i[101]: any
i[101];
let ii = { ...indexed, ...indexed2 };
// both have indexer, so i[1001]: number | boolean
ii[1001];
//// [objectSpreadIndexSignature.js]
var __assign = (this && this.__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;
};
var indexed;
var indexed2;
var i = __assign({}, indexed, { b: 11 });
// only indexed has indexer, so i[101]: any
i[101];
var ii = __assign({}, indexed, indexed2);
// both have indexer, so i[1001]: number | boolean
ii[1001];

View File

@ -0,0 +1,42 @@
=== tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts ===
interface Indexed {
>Indexed : Symbol(Indexed, Decl(objectSpreadIndexSignature.ts, 0, 0))
[n: string]: number;
>n : Symbol(n, Decl(objectSpreadIndexSignature.ts, 1, 5))
a: number;
>a : Symbol(Indexed.a, Decl(objectSpreadIndexSignature.ts, 1, 24))
}
interface Indexed2 {
>Indexed2 : Symbol(Indexed2, Decl(objectSpreadIndexSignature.ts, 3, 1))
[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))
>b : Symbol(b, Decl(objectSpreadIndexSignature.ts, 10, 21))
// only indexed has indexer, so i[101]: any
i[101];
>i : Symbol(i, Decl(objectSpreadIndexSignature.ts, 10, 3))
let ii = { ...indexed, ...indexed2 };
>ii : Symbol(ii, Decl(objectSpreadIndexSignature.ts, 13, 3))
// both have indexer, so i[1001]: number | boolean
ii[1001];
>ii : Symbol(ii, Decl(objectSpreadIndexSignature.ts, 13, 3))

View File

@ -0,0 +1,52 @@
=== tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts ===
interface Indexed {
>Indexed : Indexed
[n: string]: number;
>n : string
a: number;
>a : number
}
interface Indexed2 {
>Indexed2 : Indexed2
[n: string]: boolean;
>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 };
>i : { b: number; a: number; }
>{ ...indexed, b: 11 } : { b: number; a: number; }
>indexed : any
>b : number
>11 : 11
// only indexed has indexer, so i[101]: any
i[101];
>i[101] : any
>i : { b: number; a: number; }
>101 : 101
let ii = { ...indexed, ...indexed2 };
>ii : { [x: string]: number | boolean; c: boolean; a: number; }
>{ ...indexed, ...indexed2 } : { [x: string]: number | boolean; c: boolean; a: number; }
>indexed : any
>indexed2 : any
// both have indexer, so i[1001]: number | boolean
ii[1001];
>ii[1001] : number | boolean
>ii : { [x: string]: number | boolean; c: boolean; a: number; }
>1001 : 1001

View File

@ -0,0 +1,43 @@
//// [objectSpreadInference.ts]
interface Result<T,U,V> {
t: T;
u: U;
v: V;
}
declare function infer<T,U,V>(tuv: { ...T, ...U, a: V }): { t: T, u: U, v: V };
declare function infer2<T,U,V>(utv: { ...U, a: V, ...T }): { t: T, u: U, v: V };
function generic<W, X, Y>(w: W, x: X, y: Y) {
// should infer { t: {}, u: {}, v: {} } because there is no trailing type parameter
return infer({ ...w, ...x, a: y, b: "different type" });
}
let b: { b: number };
let c: { c: number };
// can only infer { t: {}, u: {}, v: {} }
let i1 = infer({ ...b, ...c, a: 12 });
// can only infer { t: {}, u: {}, v: {} }
let i2 = infer2({ ...b, ...c, a: 12 });
// can only infer { t: {}, u: {}, v: {} }
let i3 = generic(b, c, { a: 12 });
//// [objectSpreadInference.js]
var __assign = (this && this.__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;
};
function generic(w, x, y) {
// should infer { t: {}, u: {}, v: {} } because there is no trailing type parameter
return infer(__assign({}, w, x, { a: y, b: "different type" }));
}
var b;
var c;
// can only infer { t: {}, u: {}, v: {} }
var i1 = infer(__assign({}, b, c, { a: 12 }));
// can only infer { t: {}, u: {}, v: {} }
var i2 = infer2(__assign({}, b, c, { a: 12 }));
// can only infer { t: {}, u: {}, v: {} }
var i3 = generic(b, c, { a: 12 });

View File

@ -0,0 +1,100 @@
=== tests/cases/conformance/types/spread/objectSpreadInference.ts ===
interface Result<T,U,V> {
>Result : Symbol(Result, Decl(objectSpreadInference.ts, 0, 0))
>T : Symbol(T, Decl(objectSpreadInference.ts, 0, 17))
>U : Symbol(U, Decl(objectSpreadInference.ts, 0, 19))
>V : Symbol(V, Decl(objectSpreadInference.ts, 0, 21))
t: T;
>t : Symbol(Result.t, Decl(objectSpreadInference.ts, 0, 25))
>T : Symbol(T, Decl(objectSpreadInference.ts, 0, 17))
u: U;
>u : Symbol(Result.u, Decl(objectSpreadInference.ts, 1, 9))
>U : Symbol(U, Decl(objectSpreadInference.ts, 0, 19))
v: V;
>v : Symbol(Result.v, Decl(objectSpreadInference.ts, 2, 9))
>V : Symbol(V, Decl(objectSpreadInference.ts, 0, 21))
}
declare function infer<T,U,V>(tuv: { ...T, ...U, a: V }): { t: T, u: U, v: V };
>infer : Symbol(infer, Decl(objectSpreadInference.ts, 4, 1))
>T : Symbol(T, Decl(objectSpreadInference.ts, 5, 23))
>U : Symbol(U, Decl(objectSpreadInference.ts, 5, 25))
>V : Symbol(V, Decl(objectSpreadInference.ts, 5, 27))
>tuv : Symbol(tuv, Decl(objectSpreadInference.ts, 5, 30))
>T : Symbol(T, Decl(objectSpreadInference.ts, 5, 23))
>U : Symbol(U, Decl(objectSpreadInference.ts, 5, 25))
>a : Symbol(a, Decl(objectSpreadInference.ts, 5, 48))
>V : Symbol(V, Decl(objectSpreadInference.ts, 5, 27))
>t : Symbol(t, Decl(objectSpreadInference.ts, 5, 59))
>T : Symbol(T, Decl(objectSpreadInference.ts, 5, 23))
>u : Symbol(u, Decl(objectSpreadInference.ts, 5, 65))
>U : Symbol(U, Decl(objectSpreadInference.ts, 5, 25))
>v : Symbol(v, Decl(objectSpreadInference.ts, 5, 71))
>V : Symbol(V, Decl(objectSpreadInference.ts, 5, 27))
declare function infer2<T,U,V>(utv: { ...U, a: V, ...T }): { t: T, u: U, v: V };
>infer2 : Symbol(infer2, Decl(objectSpreadInference.ts, 5, 79))
>T : Symbol(T, Decl(objectSpreadInference.ts, 6, 24))
>U : Symbol(U, Decl(objectSpreadInference.ts, 6, 26))
>V : Symbol(V, Decl(objectSpreadInference.ts, 6, 28))
>utv : Symbol(utv, Decl(objectSpreadInference.ts, 6, 31))
>U : Symbol(U, Decl(objectSpreadInference.ts, 6, 26))
>a : Symbol(a, Decl(objectSpreadInference.ts, 6, 43))
>V : Symbol(V, Decl(objectSpreadInference.ts, 6, 28))
>T : Symbol(T, Decl(objectSpreadInference.ts, 6, 24))
>t : Symbol(t, Decl(objectSpreadInference.ts, 6, 60))
>T : Symbol(T, Decl(objectSpreadInference.ts, 6, 24))
>u : Symbol(u, Decl(objectSpreadInference.ts, 6, 66))
>U : Symbol(U, Decl(objectSpreadInference.ts, 6, 26))
>v : Symbol(v, Decl(objectSpreadInference.ts, 6, 72))
>V : Symbol(V, Decl(objectSpreadInference.ts, 6, 28))
function generic<W, X, Y>(w: W, x: X, y: Y) {
>generic : Symbol(generic, Decl(objectSpreadInference.ts, 6, 80))
>W : Symbol(W, Decl(objectSpreadInference.ts, 7, 17))
>X : Symbol(X, Decl(objectSpreadInference.ts, 7, 19))
>Y : Symbol(Y, Decl(objectSpreadInference.ts, 7, 22))
>w : Symbol(w, Decl(objectSpreadInference.ts, 7, 26))
>W : Symbol(W, Decl(objectSpreadInference.ts, 7, 17))
>x : Symbol(x, Decl(objectSpreadInference.ts, 7, 31))
>X : Symbol(X, Decl(objectSpreadInference.ts, 7, 19))
>y : Symbol(y, Decl(objectSpreadInference.ts, 7, 37))
>Y : Symbol(Y, Decl(objectSpreadInference.ts, 7, 22))
// should infer { t: {}, u: {}, v: {} } because there is no trailing type parameter
return infer({ ...w, ...x, a: y, b: "different type" });
>infer : Symbol(infer, Decl(objectSpreadInference.ts, 4, 1))
>a : Symbol(a, Decl(objectSpreadInference.ts, 9, 30))
>y : Symbol(y, Decl(objectSpreadInference.ts, 7, 37))
>b : Symbol(b, Decl(objectSpreadInference.ts, 9, 36))
}
let b: { b: number };
>b : Symbol(b, Decl(objectSpreadInference.ts, 11, 3))
>b : Symbol(b, Decl(objectSpreadInference.ts, 11, 8))
let c: { c: number };
>c : Symbol(c, Decl(objectSpreadInference.ts, 12, 3))
>c : Symbol(c, Decl(objectSpreadInference.ts, 12, 8))
// can only infer { t: {}, u: {}, v: {} }
let i1 = infer({ ...b, ...c, a: 12 });
>i1 : Symbol(i1, Decl(objectSpreadInference.ts, 14, 3))
>infer : Symbol(infer, Decl(objectSpreadInference.ts, 4, 1))
>a : Symbol(a, Decl(objectSpreadInference.ts, 14, 28))
// can only infer { t: {}, u: {}, v: {} }
let i2 = infer2({ ...b, ...c, a: 12 });
>i2 : Symbol(i2, Decl(objectSpreadInference.ts, 16, 3))
>infer2 : Symbol(infer2, Decl(objectSpreadInference.ts, 5, 79))
>a : Symbol(a, Decl(objectSpreadInference.ts, 16, 29))
// can only infer { t: {}, u: {}, v: {} }
let i3 = generic(b, c, { a: 12 });
>i3 : Symbol(i3, Decl(objectSpreadInference.ts, 18, 3))
>generic : Symbol(generic, Decl(objectSpreadInference.ts, 6, 80))
>b : Symbol(b, Decl(objectSpreadInference.ts, 11, 3))
>c : Symbol(c, Decl(objectSpreadInference.ts, 12, 3))
>a : Symbol(a, Decl(objectSpreadInference.ts, 18, 24))

View File

@ -0,0 +1,118 @@
=== tests/cases/conformance/types/spread/objectSpreadInference.ts ===
interface Result<T,U,V> {
>Result : Result<T, U, V>
>T : T
>U : U
>V : V
t: T;
>t : T
>T : T
u: U;
>u : U
>U : U
v: V;
>v : V
>V : V
}
declare function infer<T,U,V>(tuv: { ...T, ...U, a: V }): { t: T, u: U, v: V };
>infer : <T, U, V>(tuv: { ...T; ...U; a: V; }) => { t: T; u: U; v: V; }
>T : T
>U : U
>V : V
>tuv : { ...T; ...U; a: V; }
>T : T
>U : U
>a : V
>V : V
>t : T
>T : T
>u : U
>U : U
>v : V
>V : V
declare function infer2<T,U,V>(utv: { ...U, a: V, ...T }): { t: T, u: U, v: V };
>infer2 : <T, U, V>(utv: { ...U; a: V; ...T }) => { t: T; u: U; v: V; }
>T : T
>U : U
>V : V
>utv : { ...U; a: V; ...T }
>U : U
>a : V
>V : V
>T : T
>t : T
>T : T
>u : U
>U : U
>v : V
>V : V
function generic<W, X, Y>(w: W, x: X, y: Y) {
>generic : <W, X, Y>(w: W, x: X, y: Y) => { t: {}; u: {}; v: {}; }
>W : W
>X : X
>Y : Y
>w : W
>W : W
>x : X
>X : X
>y : Y
>Y : Y
// should infer { t: {}, u: {}, v: {} } because there is no trailing type parameter
return infer({ ...w, ...x, a: y, b: "different type" });
>infer({ ...w, ...x, a: y, b: "different type" }) : { t: {}; u: {}; v: {}; }
>infer : <T, U, V>(tuv: { ...T; ...U; a: V; }) => { t: T; u: U; v: V; }
>{ ...w, ...x, a: y, b: "different type" } : { ...W; ...X; a: Y; b: string; }
>w : any
>x : any
>a : Y
>y : Y
>b : string
>"different type" : "different type"
}
let b: { b: number };
>b : { b: number; }
>b : number
let c: { c: number };
>c : { c: number; }
>c : number
// can only infer { t: {}, u: {}, v: {} }
let i1 = infer({ ...b, ...c, a: 12 });
>i1 : { t: {}; u: {}; v: {}; }
>infer({ ...b, ...c, a: 12 }) : { t: {}; u: {}; v: {}; }
>infer : <T, U, V>(tuv: { ...T; ...U; a: V; }) => { t: T; u: U; v: V; }
>{ ...b, ...c, a: 12 } : { a: number; c: number; b: number; }
>b : any
>c : any
>a : number
>12 : 12
// can only infer { t: {}, u: {}, v: {} }
let i2 = infer2({ ...b, ...c, a: 12 });
>i2 : { t: {}; u: {}; v: {}; }
>infer2({ ...b, ...c, a: 12 }) : { t: {}; u: {}; v: {}; }
>infer2 : <T, U, V>(utv: { ...U; a: V; ...T }) => { t: T; u: U; v: V; }
>{ ...b, ...c, a: 12 } : { a: number; c: number; b: number; }
>b : any
>c : any
>a : number
>12 : 12
// can only infer { t: {}, u: {}, v: {} }
let i3 = generic(b, c, { a: 12 });
>i3 : { t: {}; u: {}; v: {}; }
>generic(b, c, { a: 12 }) : { t: {}; u: {}; v: {}; }
>generic : <W, X, Y>(w: W, x: X, y: Y) => { t: {}; u: {}; v: {}; }
>b : { b: number; }
>c : { c: number; }
>{ a: 12 } : { a: number; }
>a : number
>12 : 12

View File

@ -0,0 +1,77 @@
//// [objectSpreadIntersection.ts]
function iteratedUnionIntersection<T, U, V>(t: T, u: U, v: V): void {
let tu: T | U;
let uv: U & V;
let result = { ...tu, ...uv, id: 'foo' };
let assignable: { ...(T | U), ...(U & V), id: string } = result;
}
// concrete types work
interface A1 { a: number }
interface A2 { a: string }
interface B1 { b: number }
interface B2 { b: string }
let a12: A1 & A2;
let b12: B1 & B2;
let result = { ...a12, ...b12 };
let sn: number & string = result.a;
sn = result.b;
let assignable: { ...(A1 & A2), ...(B1 & B2) } = result;
function tripleIntersection<T, U, V>(t: T, u: U, v: V): void {
let tuv: T & U & V;
let result = { ...tuv, id: 'bar' };
let assignable: { ...(T & U & V), id: string } = result;
}
function iteratedDoubleIntersection<T, U, V>(t: T, u: U, v: V): void {
let tu: T & U;
let uv: U & V;
let result = { ...tu, ...uv, id: 'baz' };
let assignable: { ...(T & U), ...(U & V), id: string } = result;
}
function iteratedIntersectionUnion<T, U, V>(t: T, u: U, v: V): void {
let tu: T & U;
let uv: U | V;
let result = { ...tu, ...uv, id: 'qux' };
let assignable: { ...(T & U), ...(U | V), id: string } = result;
}
//// [objectSpreadIntersection.js]
var __assign = (this && this.__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;
};
function iteratedUnionIntersection(t, u, v) {
var tu;
var uv;
var result = __assign({}, tu, uv, { id: 'foo' });
var assignable = result;
}
var a12;
var b12;
var result = __assign({}, a12, b12);
var sn = result.a;
sn = result.b;
var assignable = result;
function tripleIntersection(t, u, v) {
var tuv;
var result = __assign({}, tuv, { id: 'bar' });
var assignable = result;
}
function iteratedDoubleIntersection(t, u, v) {
var tu;
var uv;
var result = __assign({}, tu, uv, { id: 'baz' });
var assignable = result;
}
function iteratedIntersectionUnion(t, u, v) {
var tu;
var uv;
var result = __assign({}, tu, uv, { id: 'qux' });
var assignable = result;
}

View File

@ -0,0 +1,188 @@
=== tests/cases/conformance/types/spread/objectSpreadIntersection.ts ===
function iteratedUnionIntersection<T, U, V>(t: T, u: U, v: V): void {
>iteratedUnionIntersection : Symbol(iteratedUnionIntersection, Decl(objectSpreadIntersection.ts, 0, 0))
>T : Symbol(T, Decl(objectSpreadIntersection.ts, 0, 35))
>U : Symbol(U, Decl(objectSpreadIntersection.ts, 0, 37))
>V : Symbol(V, Decl(objectSpreadIntersection.ts, 0, 40))
>t : Symbol(t, Decl(objectSpreadIntersection.ts, 0, 44))
>T : Symbol(T, Decl(objectSpreadIntersection.ts, 0, 35))
>u : Symbol(u, Decl(objectSpreadIntersection.ts, 0, 49))
>U : Symbol(U, Decl(objectSpreadIntersection.ts, 0, 37))
>v : Symbol(v, Decl(objectSpreadIntersection.ts, 0, 55))
>V : Symbol(V, Decl(objectSpreadIntersection.ts, 0, 40))
let tu: T | U;
>tu : Symbol(tu, Decl(objectSpreadIntersection.ts, 1, 7))
>T : Symbol(T, Decl(objectSpreadIntersection.ts, 0, 35))
>U : Symbol(U, Decl(objectSpreadIntersection.ts, 0, 37))
let uv: U & V;
>uv : Symbol(uv, Decl(objectSpreadIntersection.ts, 2, 7))
>U : Symbol(U, Decl(objectSpreadIntersection.ts, 0, 37))
>V : Symbol(V, Decl(objectSpreadIntersection.ts, 0, 40))
let result = { ...tu, ...uv, id: 'foo' };
>result : Symbol(result, Decl(objectSpreadIntersection.ts, 3, 7))
>id : Symbol(id, Decl(objectSpreadIntersection.ts, 3, 32))
let assignable: { ...(T | U), ...(U & V), id: string } = result;
>assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 4, 7))
>T : Symbol(T, Decl(objectSpreadIntersection.ts, 0, 35))
>U : Symbol(U, Decl(objectSpreadIntersection.ts, 0, 37))
>U : Symbol(U, Decl(objectSpreadIntersection.ts, 0, 37))
>V : Symbol(V, Decl(objectSpreadIntersection.ts, 0, 40))
>id : Symbol(id, Decl(objectSpreadIntersection.ts, 4, 45))
>result : Symbol(result, Decl(objectSpreadIntersection.ts, 3, 7))
}
// concrete types work
interface A1 { a: number }
>A1 : Symbol(A1, Decl(objectSpreadIntersection.ts, 5, 1))
>a : Symbol(A1.a, Decl(objectSpreadIntersection.ts, 7, 14))
interface A2 { a: string }
>A2 : Symbol(A2, Decl(objectSpreadIntersection.ts, 7, 26))
>a : Symbol(A2.a, Decl(objectSpreadIntersection.ts, 8, 14))
interface B1 { b: number }
>B1 : Symbol(B1, Decl(objectSpreadIntersection.ts, 8, 26))
>b : Symbol(B1.b, Decl(objectSpreadIntersection.ts, 9, 14))
interface B2 { b: string }
>B2 : Symbol(B2, Decl(objectSpreadIntersection.ts, 9, 26))
>b : Symbol(B2.b, Decl(objectSpreadIntersection.ts, 10, 14))
let a12: A1 & A2;
>a12 : Symbol(a12, Decl(objectSpreadIntersection.ts, 11, 3))
>A1 : Symbol(A1, Decl(objectSpreadIntersection.ts, 5, 1))
>A2 : Symbol(A2, Decl(objectSpreadIntersection.ts, 7, 26))
let b12: B1 & B2;
>b12 : Symbol(b12, Decl(objectSpreadIntersection.ts, 12, 3))
>B1 : Symbol(B1, Decl(objectSpreadIntersection.ts, 8, 26))
>B2 : Symbol(B2, Decl(objectSpreadIntersection.ts, 9, 26))
let result = { ...a12, ...b12 };
>result : Symbol(result, Decl(objectSpreadIntersection.ts, 13, 3))
let sn: number & string = result.a;
>sn : Symbol(sn, Decl(objectSpreadIntersection.ts, 14, 3))
>result.a : Symbol(a, Decl(objectSpreadIntersection.ts, 7, 14), Decl(objectSpreadIntersection.ts, 8, 14))
>result : Symbol(result, Decl(objectSpreadIntersection.ts, 13, 3))
>a : Symbol(a, Decl(objectSpreadIntersection.ts, 7, 14), Decl(objectSpreadIntersection.ts, 8, 14))
sn = result.b;
>sn : Symbol(sn, Decl(objectSpreadIntersection.ts, 14, 3))
>result.b : Symbol(b, Decl(objectSpreadIntersection.ts, 9, 14), Decl(objectSpreadIntersection.ts, 10, 14))
>result : Symbol(result, Decl(objectSpreadIntersection.ts, 13, 3))
>b : Symbol(b, Decl(objectSpreadIntersection.ts, 9, 14), Decl(objectSpreadIntersection.ts, 10, 14))
let assignable: { ...(A1 & A2), ...(B1 & B2) } = result;
>assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 16, 3))
>A1 : Symbol(A1, Decl(objectSpreadIntersection.ts, 5, 1))
>A2 : Symbol(A2, Decl(objectSpreadIntersection.ts, 7, 26))
>B1 : Symbol(B1, Decl(objectSpreadIntersection.ts, 8, 26))
>B2 : Symbol(B2, Decl(objectSpreadIntersection.ts, 9, 26))
>result : Symbol(result, Decl(objectSpreadIntersection.ts, 13, 3))
function tripleIntersection<T, U, V>(t: T, u: U, v: V): void {
>tripleIntersection : Symbol(tripleIntersection, Decl(objectSpreadIntersection.ts, 16, 56))
>T : Symbol(T, Decl(objectSpreadIntersection.ts, 18, 28))
>U : Symbol(U, Decl(objectSpreadIntersection.ts, 18, 30))
>V : Symbol(V, Decl(objectSpreadIntersection.ts, 18, 33))
>t : Symbol(t, Decl(objectSpreadIntersection.ts, 18, 37))
>T : Symbol(T, Decl(objectSpreadIntersection.ts, 18, 28))
>u : Symbol(u, Decl(objectSpreadIntersection.ts, 18, 42))
>U : Symbol(U, Decl(objectSpreadIntersection.ts, 18, 30))
>v : Symbol(v, Decl(objectSpreadIntersection.ts, 18, 48))
>V : Symbol(V, Decl(objectSpreadIntersection.ts, 18, 33))
let tuv: T & U & V;
>tuv : Symbol(tuv, Decl(objectSpreadIntersection.ts, 19, 7))
>T : Symbol(T, Decl(objectSpreadIntersection.ts, 18, 28))
>U : Symbol(U, Decl(objectSpreadIntersection.ts, 18, 30))
>V : Symbol(V, Decl(objectSpreadIntersection.ts, 18, 33))
let result = { ...tuv, id: 'bar' };
>result : Symbol(result, Decl(objectSpreadIntersection.ts, 20, 7))
>id : Symbol(id, Decl(objectSpreadIntersection.ts, 20, 26))
let assignable: { ...(T & U & V), id: string } = result;
>assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 21, 7))
>T : Symbol(T, Decl(objectSpreadIntersection.ts, 18, 28))
>U : Symbol(U, Decl(objectSpreadIntersection.ts, 18, 30))
>V : Symbol(V, Decl(objectSpreadIntersection.ts, 18, 33))
>id : Symbol(id, Decl(objectSpreadIntersection.ts, 21, 37))
>result : Symbol(result, Decl(objectSpreadIntersection.ts, 20, 7))
}
function iteratedDoubleIntersection<T, U, V>(t: T, u: U, v: V): void {
>iteratedDoubleIntersection : Symbol(iteratedDoubleIntersection, Decl(objectSpreadIntersection.ts, 22, 1))
>T : Symbol(T, Decl(objectSpreadIntersection.ts, 23, 36))
>U : Symbol(U, Decl(objectSpreadIntersection.ts, 23, 38))
>V : Symbol(V, Decl(objectSpreadIntersection.ts, 23, 41))
>t : Symbol(t, Decl(objectSpreadIntersection.ts, 23, 45))
>T : Symbol(T, Decl(objectSpreadIntersection.ts, 23, 36))
>u : Symbol(u, Decl(objectSpreadIntersection.ts, 23, 50))
>U : Symbol(U, Decl(objectSpreadIntersection.ts, 23, 38))
>v : Symbol(v, Decl(objectSpreadIntersection.ts, 23, 56))
>V : Symbol(V, Decl(objectSpreadIntersection.ts, 23, 41))
let tu: T & U;
>tu : Symbol(tu, Decl(objectSpreadIntersection.ts, 24, 7))
>T : Symbol(T, Decl(objectSpreadIntersection.ts, 23, 36))
>U : Symbol(U, Decl(objectSpreadIntersection.ts, 23, 38))
let uv: U & V;
>uv : Symbol(uv, Decl(objectSpreadIntersection.ts, 25, 7))
>U : Symbol(U, Decl(objectSpreadIntersection.ts, 23, 38))
>V : Symbol(V, Decl(objectSpreadIntersection.ts, 23, 41))
let result = { ...tu, ...uv, id: 'baz' };
>result : Symbol(result, Decl(objectSpreadIntersection.ts, 26, 7))
>id : Symbol(id, Decl(objectSpreadIntersection.ts, 26, 32))
let assignable: { ...(T & U), ...(U & V), id: string } = result;
>assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 27, 7))
>T : Symbol(T, Decl(objectSpreadIntersection.ts, 23, 36))
>U : Symbol(U, Decl(objectSpreadIntersection.ts, 23, 38))
>U : Symbol(U, Decl(objectSpreadIntersection.ts, 23, 38))
>V : Symbol(V, Decl(objectSpreadIntersection.ts, 23, 41))
>id : Symbol(id, Decl(objectSpreadIntersection.ts, 27, 45))
>result : Symbol(result, Decl(objectSpreadIntersection.ts, 26, 7))
}
function iteratedIntersectionUnion<T, U, V>(t: T, u: U, v: V): void {
>iteratedIntersectionUnion : Symbol(iteratedIntersectionUnion, Decl(objectSpreadIntersection.ts, 28, 1))
>T : Symbol(T, Decl(objectSpreadIntersection.ts, 29, 35))
>U : Symbol(U, Decl(objectSpreadIntersection.ts, 29, 37))
>V : Symbol(V, Decl(objectSpreadIntersection.ts, 29, 40))
>t : Symbol(t, Decl(objectSpreadIntersection.ts, 29, 44))
>T : Symbol(T, Decl(objectSpreadIntersection.ts, 29, 35))
>u : Symbol(u, Decl(objectSpreadIntersection.ts, 29, 49))
>U : Symbol(U, Decl(objectSpreadIntersection.ts, 29, 37))
>v : Symbol(v, Decl(objectSpreadIntersection.ts, 29, 55))
>V : Symbol(V, Decl(objectSpreadIntersection.ts, 29, 40))
let tu: T & U;
>tu : Symbol(tu, Decl(objectSpreadIntersection.ts, 30, 7))
>T : Symbol(T, Decl(objectSpreadIntersection.ts, 29, 35))
>U : Symbol(U, Decl(objectSpreadIntersection.ts, 29, 37))
let uv: U | V;
>uv : Symbol(uv, Decl(objectSpreadIntersection.ts, 31, 7))
>U : Symbol(U, Decl(objectSpreadIntersection.ts, 29, 37))
>V : Symbol(V, Decl(objectSpreadIntersection.ts, 29, 40))
let result = { ...tu, ...uv, id: 'qux' };
>result : Symbol(result, Decl(objectSpreadIntersection.ts, 32, 7))
>id : Symbol(id, Decl(objectSpreadIntersection.ts, 32, 32))
let assignable: { ...(T & U), ...(U | V), id: string } = result;
>assignable : Symbol(assignable, Decl(objectSpreadIntersection.ts, 33, 7))
>T : Symbol(T, Decl(objectSpreadIntersection.ts, 29, 35))
>U : Symbol(U, Decl(objectSpreadIntersection.ts, 29, 37))
>U : Symbol(U, Decl(objectSpreadIntersection.ts, 29, 37))
>V : Symbol(V, Decl(objectSpreadIntersection.ts, 29, 40))
>id : Symbol(id, Decl(objectSpreadIntersection.ts, 33, 45))
>result : Symbol(result, Decl(objectSpreadIntersection.ts, 32, 7))
}

View File

@ -0,0 +1,207 @@
=== tests/cases/conformance/types/spread/objectSpreadIntersection.ts ===
function iteratedUnionIntersection<T, U, V>(t: T, u: U, v: V): void {
>iteratedUnionIntersection : <T, U, V>(t: T, u: U, v: V) => void
>T : T
>U : U
>V : V
>t : T
>T : T
>u : U
>U : U
>v : V
>V : V
let tu: T | U;
>tu : T | U
>T : T
>U : U
let uv: U & V;
>uv : U & V
>U : U
>V : V
let result = { ...tu, ...uv, id: 'foo' };
>result : { ...T; ...U & V; id: string; } | { ...U; ...U & V; id: string; }
>{ ...tu, ...uv, id: 'foo' } : { ...T; ...U & V; id: string; } | { ...U; ...U & V; id: string; }
>tu : any
>uv : any
>id : string
>'foo' : "foo"
let assignable: { ...(T | U), ...(U & V), id: string } = result;
>assignable : { ...T; ...U & V; id: string; } | { ...U; ...U & V; id: string; }
>T : T
>U : U
>U : U
>V : V
>id : string
>result : { ...T; ...U & V; id: string; } | { ...U; ...U & V; id: string; }
}
// concrete types work
interface A1 { a: number }
>A1 : A1
>a : number
interface A2 { a: string }
>A2 : A2
>a : string
interface B1 { b: number }
>B1 : B1
>b : number
interface B2 { b: string }
>B2 : B2
>b : string
let a12: A1 & A2;
>a12 : A1 & A2
>A1 : A1
>A2 : A2
let b12: B1 & B2;
>b12 : B1 & B2
>B1 : B1
>B2 : B2
let result = { ...a12, ...b12 };
>result : { b: number & string; a: number & string; }
>{ ...a12, ...b12 } : { b: number & string; a: number & string; }
>a12 : any
>b12 : any
let sn: number & string = result.a;
>sn : number & string
>result.a : number & string
>result : { b: number & string; a: number & string; }
>a : number & string
sn = result.b;
>sn = result.b : number & string
>sn : number & string
>result.b : number & string
>result : { b: number & string; a: number & string; }
>b : number & string
let assignable: { ...(A1 & A2), ...(B1 & B2) } = result;
>assignable : { b: number & string; a: number & string; }
>A1 : A1
>A2 : A2
>B1 : B1
>B2 : B2
>result : { b: number & string; a: number & string; }
function tripleIntersection<T, U, V>(t: T, u: U, v: V): void {
>tripleIntersection : <T, U, V>(t: T, u: U, v: V) => void
>T : T
>U : U
>V : V
>t : T
>T : T
>u : U
>U : U
>v : V
>V : V
let tuv: T & U & V;
>tuv : T & U & V
>T : T
>U : U
>V : V
let result = { ...tuv, id: 'bar' };
>result : { ...T & U & V; id: string; }
>{ ...tuv, id: 'bar' } : { ...T & U & V; id: string; }
>tuv : any
>id : string
>'bar' : "bar"
let assignable: { ...(T & U & V), id: string } = result;
>assignable : { ...T & U & V; id: string; }
>T : T
>U : U
>V : V
>id : string
>result : { ...T & U & V; id: string; }
}
function iteratedDoubleIntersection<T, U, V>(t: T, u: U, v: V): void {
>iteratedDoubleIntersection : <T, U, V>(t: T, u: U, v: V) => void
>T : T
>U : U
>V : V
>t : T
>T : T
>u : U
>U : U
>v : V
>V : V
let tu: T & U;
>tu : T & U
>T : T
>U : U
let uv: U & V;
>uv : U & V
>U : U
>V : V
let result = { ...tu, ...uv, id: 'baz' };
>result : { ...T & U; ...U & V; id: string; }
>{ ...tu, ...uv, id: 'baz' } : { ...T & U; ...U & V; id: string; }
>tu : any
>uv : any
>id : string
>'baz' : "baz"
let assignable: { ...(T & U), ...(U & V), id: string } = result;
>assignable : { ...T & U; ...U & V; id: string; }
>T : T
>U : U
>U : U
>V : V
>id : string
>result : { ...T & U; ...U & V; id: string; }
}
function iteratedIntersectionUnion<T, U, V>(t: T, u: U, v: V): void {
>iteratedIntersectionUnion : <T, U, V>(t: T, u: U, v: V) => void
>T : T
>U : U
>V : V
>t : T
>T : T
>u : U
>U : U
>v : V
>V : V
let tu: T & U;
>tu : T & U
>T : T
>U : U
let uv: U | V;
>uv : U | V
>U : U
>V : V
let result = { ...tu, ...uv, id: 'qux' };
>result : { ...T & U; ...U; id: string; } | { ...T & U; ...V; id: string; }
>{ ...tu, ...uv, id: 'qux' } : { ...T & U; ...U; id: string; } | { ...T & U; ...V; id: string; }
>tu : any
>uv : any
>id : string
>'qux' : "qux"
let assignable: { ...(T & U), ...(U | V), id: string } = result;
>assignable : { ...T & U; ...U; id: string; } | { ...T & U; ...V; id: string; }
>T : T
>U : U
>U : U
>V : V
>id : string
>result : { ...T & U; ...U; id: string; } | { ...T & U; ...V; id: string; }
}

View File

@ -0,0 +1,131 @@
tests/cases/conformance/types/spread/objectSpreadNegative.ts(13,21): error TS2339: Property 'x' does not exist on type '{}'.
tests/cases/conformance/types/spread/objectSpreadNegative.ts(16,5): error TS2322: Type '{ sn?: string | number; }' is not assignable to type '{ sn: string | number; }'.
Property 'sn' is optional in type '{ sn?: string | number; }' but required in type '{ sn: string | number; }'.
tests/cases/conformance/types/spread/objectSpreadNegative.ts(23,1): error TS2322: Type '{ s: string; }' is not assignable to type '{ s: string; b: boolean; }'.
Property 'b' is missing in type '{ s: string; }'.
tests/cases/conformance/types/spread/objectSpreadNegative.ts(25,1): error TS2322: Type '{ b: boolean; }' is not assignable to type '{ s: string; b: boolean; }'.
Property 's' is missing in type '{ b: boolean; }'.
tests/cases/conformance/types/spread/objectSpreadNegative.ts(28,36): error TS2300: Duplicate identifier 'b'.
tests/cases/conformance/types/spread/objectSpreadNegative.ts(28,53): error TS2300: Duplicate identifier 'b'.
tests/cases/conformance/types/spread/objectSpreadNegative.ts(32,20): error TS2698: Spread types may only be created from object types.
tests/cases/conformance/types/spread/objectSpreadNegative.ts(33,24): error TS2698: Spread types may only be created from object types.
tests/cases/conformance/types/spread/objectSpreadNegative.ts(34,19): error TS2698: Spread types may only be created from object types.
tests/cases/conformance/types/spread/objectSpreadNegative.ts(35,19): error TS2698: Spread types may only be created from object types.
tests/cases/conformance/types/spread/objectSpreadNegative.ts(37,20): error TS2698: Spread types may only be created from object types.
tests/cases/conformance/types/spread/objectSpreadNegative.ts(39,19): error TS2698: Spread types may only be created from object types.
tests/cases/conformance/types/spread/objectSpreadNegative.ts(44,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{}' has no compatible call signatures.
tests/cases/conformance/types/spread/objectSpreadNegative.ts(48,12): error TS2339: Property 'b' does not exist on type '{}'.
tests/cases/conformance/types/spread/objectSpreadNegative.ts(54,9): error TS2339: Property 'm' does not exist on type '{ p: number; }'.
tests/cases/conformance/types/spread/objectSpreadNegative.ts(58,14): error TS2698: Spread types may only be created from object types.
tests/cases/conformance/types/spread/objectSpreadNegative.ts(61,14): error TS2698: Spread types may only be created from object types.
==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (17 errors) ====
let o = { a: 1, b: 'no' }
/// private propagates
class PrivateOptionalX {
private x?: number;
}
class PublicX {
public x: number;
}
let publicX: PublicX;
let privateOptionalX: PrivateOptionalX;
let o2 = { ...publicX, ...privateOptionalX };
let sn: number = o2.x; // error, x is private
~
!!! error TS2339: Property 'x' does not exist on type '{}'.
let optionalString: { sn?: string };
let optionalNumber: { sn?: number };
let allOptional: { sn: string | number } = { ...optionalString, ...optionalNumber };
~~~~~~~~~~~
!!! error TS2322: Type '{ sn?: string | number; }' is not assignable to type '{ sn: string | number; }'.
!!! error TS2322: Property 'sn' is optional in type '{ sn?: string | number; }' but required in type '{ sn: string | number; }'.
// error, 'sn' is optional in source, required in target
// assignability as target
interface Bool { b: boolean };
interface Str { s: string };
let spread = { ...{ b: true }, ...{s: "foo" } };
spread = { s: "foo" }; // error, missing 'b'
~~~~~~
!!! error TS2322: Type '{ s: string; }' is not assignable to type '{ s: string; b: boolean; }'.
!!! error TS2322: Property 'b' is missing in type '{ s: string; }'.
let b = { b: false };
spread = b; // error, missing 's'
~~~~~~
!!! error TS2322: Type '{ b: boolean; }' is not assignable to type '{ s: string; b: boolean; }'.
!!! error TS2322: Property 's' is missing in type '{ b: boolean; }'.
// literal repeats are not allowed, but spread repeats are fine
let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' }
~
!!! error TS2300: Duplicate identifier 'b'.
~
!!! error TS2300: Duplicate identifier 'b'.
let duplicatedSpread = { ...o, ...o }
// null, undefined and primitives are not allowed
let spreadNull = { ...null };
~~~~~~~
!!! error TS2698: Spread types may only be created from object types.
let spreadUndefind = { ...undefined };
~~~~~~~~~~~~
!!! error TS2698: Spread types may only be created from object types.
let spreadNum = { ...12 };
~~~~~
!!! error TS2698: Spread types may only be created from object types.
let spreadSum = { ...1 + 1 };
~~~~~~~~
!!! error TS2698: Spread types may only be created from object types.
spreadSum.toFixed(); // error, no methods from number
let spreadBool = { ...false };
~~~~~~~~
!!! error TS2698: Spread types may only be created from object types.
spreadBool.valueOf(); // error, what were you thinking?
let spreadStr = { ...'foo' };
~~~~~~~~
!!! error TS2698: Spread types may only be created from object types.
spreadStr.length; // error, no 'length'
spreadStr.charAt(1); // error, no methods either
// functions are skipped
let spreadFunc = { ...function () { } }
spreadFunc(); // error, no call signature
~~~~~~~~~~~~
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{}' has no compatible call signatures.
// write-only properties get skipped
let setterOnly = { ...{ set b (bad: number) { } } };
setterOnly.b = 12; // error, 'b' does not exist
~
!!! error TS2339: Property 'b' does not exist on type '{}'.
// methods are skipped because they aren't enumerable
class C { p = 1; m() { } }
let c: C = new C()
let spreadC = { ...c }
spreadC.m(); // error 'm' is not in '{ ... c }'
~
!!! error TS2339: Property 'm' does not exist on type '{ p: number; }'.
// generics
function f<T, U>(t: T, u: U) {
return { ...t, ...u, id: 'id' };
~~~~
!!! error TS2698: Spread types may only be created from object types.
}
function override<U>(initial: U, override: U): U {
return { ...initial, ...override };
~~~~~~~~~~
!!! error TS2698: Spread types may only be created from object types.
}
let exclusive: { id: string, a: number, b: string, c: string, d: boolean } =
f({ a: 1, b: 'yes' }, { c: 'no', d: false })
let overlap: { id: string, a: number, b: string } =
f({ a: 1 }, { a: 2, b: 'extra' })
let overlapConflict: { id:string, a: string } =
f({ a: 1 }, { a: 'mismatch' })
let overwriteId: { id: string, a: number, c: number, d: string } =
f({ a: 1, id: true }, { c: 1, d: 'no' })

View File

@ -0,0 +1,149 @@
//// [objectSpreadNegative.ts]
let o = { a: 1, b: 'no' }
/// private propagates
class PrivateOptionalX {
private x?: number;
}
class PublicX {
public x: number;
}
let publicX: PublicX;
let privateOptionalX: PrivateOptionalX;
let o2 = { ...publicX, ...privateOptionalX };
let sn: number = o2.x; // error, x is private
let optionalString: { sn?: string };
let optionalNumber: { sn?: number };
let allOptional: { sn: string | number } = { ...optionalString, ...optionalNumber };
// error, 'sn' is optional in source, required in target
// assignability as target
interface Bool { b: boolean };
interface Str { s: string };
let spread = { ...{ b: true }, ...{s: "foo" } };
spread = { s: "foo" }; // error, missing 'b'
let b = { b: false };
spread = b; // error, missing 's'
// literal repeats are not allowed, but spread repeats are fine
let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' }
let duplicatedSpread = { ...o, ...o }
// null, undefined and primitives are not allowed
let spreadNull = { ...null };
let spreadUndefind = { ...undefined };
let spreadNum = { ...12 };
let spreadSum = { ...1 + 1 };
spreadSum.toFixed(); // error, no methods from number
let spreadBool = { ...false };
spreadBool.valueOf(); // error, what were you thinking?
let spreadStr = { ...'foo' };
spreadStr.length; // error, no 'length'
spreadStr.charAt(1); // error, no methods either
// functions are skipped
let spreadFunc = { ...function () { } }
spreadFunc(); // error, no call signature
// write-only properties get skipped
let setterOnly = { ...{ set b (bad: number) { } } };
setterOnly.b = 12; // error, 'b' does not exist
// methods are skipped because they aren't enumerable
class C { p = 1; m() { } }
let c: C = new C()
let spreadC = { ...c }
spreadC.m(); // error 'm' is not in '{ ... c }'
// generics
function f<T, U>(t: T, u: U) {
return { ...t, ...u, id: 'id' };
}
function override<U>(initial: U, override: U): U {
return { ...initial, ...override };
}
let exclusive: { id: string, a: number, b: string, c: string, d: boolean } =
f({ a: 1, b: 'yes' }, { c: 'no', d: false })
let overlap: { id: string, a: number, b: string } =
f({ a: 1 }, { a: 2, b: 'extra' })
let overlapConflict: { id:string, a: string } =
f({ a: 1 }, { a: 'mismatch' })
let overwriteId: { id: string, a: number, c: number, d: string } =
f({ a: 1, id: true }, { c: 1, d: 'no' })
//// [objectSpreadNegative.js]
var __assign = (this && this.__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;
};
var o = { a: 1, b: 'no' };
/// private propagates
var PrivateOptionalX = (function () {
function PrivateOptionalX() {
}
return PrivateOptionalX;
}());
var PublicX = (function () {
function PublicX() {
}
return PublicX;
}());
var publicX;
var privateOptionalX;
var o2 = __assign({}, publicX, privateOptionalX);
var sn = o2.x; // error, x is private
var optionalString;
var optionalNumber;
var allOptional = __assign({}, optionalString, optionalNumber);
;
;
var spread = __assign({ b: true }, { s: "foo" });
spread = { s: "foo" }; // error, missing 'b'
var b = { b: false };
spread = b; // error, missing 's'
// literal repeats are not allowed, but spread repeats are fine
var duplicated = __assign({ b: 'bad' }, o, { b: 'bad' }, o2, { b: 'bad' });
var duplicatedSpread = __assign({}, o, o);
// null, undefined and primitives are not allowed
var spreadNull = __assign({}, null);
var spreadUndefind = __assign({}, undefined);
var spreadNum = __assign({}, 12);
var spreadSum = __assign({}, 1 + 1);
spreadSum.toFixed(); // error, no methods from number
var spreadBool = __assign({}, false);
spreadBool.valueOf(); // error, what were you thinking?
var spreadStr = __assign({}, 'foo');
spreadStr.length; // error, no 'length'
spreadStr.charAt(1); // error, no methods either
// functions are skipped
var spreadFunc = __assign({}, function () { });
spreadFunc(); // error, no call signature
// write-only properties get skipped
var setterOnly = __assign({ set b(bad) { } });
setterOnly.b = 12; // error, 'b' does not exist
// methods are skipped because they aren't enumerable
var C = (function () {
function C() {
this.p = 1;
}
C.prototype.m = function () { };
return C;
}());
var c = new C();
var spreadC = __assign({}, c);
spreadC.m(); // error 'm' is not in '{ ... c }'
// generics
function f(t, u) {
return __assign({}, t, u, { id: 'id' });
}
function override(initial, override) {
return __assign({}, initial, override);
}
var exclusive = f({ a: 1, b: 'yes' }, { c: 'no', d: false });
var overlap = f({ a: 1 }, { a: 2, b: 'extra' });
var overlapConflict = f({ a: 1 }, { a: 'mismatch' });
var overwriteId = f({ a: 1, id: true }, { c: 1, d: 'no' });

View File

@ -0,0 +1,38 @@
tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(1,15): error TS2304: Cannot find name 'o'.
tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(1,18): error TS1109: Expression expected.
tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(2,12): error TS2698: Spread types may only be created from object types.
tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(2,15): error TS1109: Expression expected.
tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(2,16): error TS2304: Cannot find name 'o'.
tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(3,15): error TS2304: Cannot find name 'matchMedia'.
tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(3,28): error TS1005: ',' expected.
tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(3,31): error TS1128: Declaration or statement expected.
tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(4,16): error TS2304: Cannot find name 'get'.
tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts(4,20): error TS1005: ',' expected.
==== tests/cases/conformance/types/spread/objectSpreadNegativeParse.ts (10 errors) ====
let o7 = { ...o? };
~
!!! error TS2304: Cannot find name 'o'.
~
!!! error TS1109: Expression expected.
let o8 = { ...*o };
~~~~~
!!! error TS2698: Spread types may only be created from object types.
~
!!! error TS1109: Expression expected.
~
!!! error TS2304: Cannot find name 'o'.
let o9 = { ...matchMedia() { }};
~~~~~~~~~~
!!! error TS2304: Cannot find name 'matchMedia'.
~
!!! error TS1005: ',' expected.
~
!!! error TS1128: Declaration or statement expected.
let o10 = { ...get x() { return 12; }};
~~~
!!! error TS2304: Cannot find name 'get'.
~
!!! error TS1005: ',' expected.

View File

@ -0,0 +1,21 @@
//// [objectSpreadNegativeParse.ts]
let o7 = { ...o? };
let o8 = { ...*o };
let o9 = { ...matchMedia() { }};
let o10 = { ...get x() { return 12; }};
//// [objectSpreadNegativeParse.js]
var __assign = (this && this.__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;
};
var o7 = __assign({}, o ? : );
var o8 = __assign({}, * o);
var o9 = __assign({}, matchMedia()), _a = void 0;
;
var o10 = __assign({}, get, { x: function () { return 12; } });

View File

@ -0,0 +1,14 @@
//// [objectSpreadNoTransform.ts]
const y = { a: 'yes', b: 'no' };
const o = { x: 1, ...y };
var b;
var rest;
({ b, ...rest } = o);
//// [objectSpreadNoTransform.js]
const y = { a: 'yes', b: 'no' };
const o = { x: 1, ...y };
var b;
var rest;
({ b, ...rest } = o);

View File

@ -0,0 +1,20 @@
=== tests/cases/conformance/types/spread/objectSpreadNoTransform.ts ===
const y = { a: 'yes', b: 'no' };
>y : Symbol(y, Decl(objectSpreadNoTransform.ts, 0, 5))
>a : Symbol(a, Decl(objectSpreadNoTransform.ts, 0, 11))
>b : Symbol(b, Decl(objectSpreadNoTransform.ts, 0, 21))
const o = { x: 1, ...y };
>o : Symbol(o, Decl(objectSpreadNoTransform.ts, 1, 5))
>x : Symbol(x, Decl(objectSpreadNoTransform.ts, 1, 11))
var b;
>b : Symbol(b, Decl(objectSpreadNoTransform.ts, 2, 3))
var rest;
>rest : Symbol(rest, Decl(objectSpreadNoTransform.ts, 3, 3))
({ b, ...rest } = o);
>b : Symbol(b, Decl(objectSpreadNoTransform.ts, 4, 2))
>o : Symbol(o, Decl(objectSpreadNoTransform.ts, 1, 5))

View File

@ -0,0 +1,30 @@
=== tests/cases/conformance/types/spread/objectSpreadNoTransform.ts ===
const y = { a: 'yes', b: 'no' };
>y : { a: string; b: string; }
>{ a: 'yes', b: 'no' } : { a: string; b: string; }
>a : string
>'yes' : "yes"
>b : string
>'no' : "no"
const o = { x: 1, ...y };
>o : { a: string; b: string; x: number; }
>{ x: 1, ...y } : { a: string; b: string; x: number; }
>x : number
>1 : 1
>y : any
var b;
>b : any
var rest;
>rest : any
({ b, ...rest } = o);
>({ b, ...rest } = o) : { a: string; b: string; x: number; }
>{ b, ...rest } = o : { a: string; b: string; x: number; }
>{ b, ...rest } : any
>b : any
>rest : any
>o : { a: string; b: string; x: number; }

View File

@ -0,0 +1,45 @@
//// [objectSpreadScenarios.ts]
interface A1 { a: boolean }
interface B1 { b: number };
function override<U>(initial: U, override: U): { ...U, ...U } {
return { ...initial, ...override };
}
function update<U>(this: { u: { ...U } }, override: U): void {
this.u = { ...this.u, ...override };
}
function mixin<T, U>(one: T, two: U): { ...T, ...U } {
return { ...one, ...two };
}
let a1: A1 = { a: true };
let b1: B1 = { b: 101 };
a1 = override(a1, { a: false });
let host = { u: a1, update };
host.update({ a: false });
let mixed = mixin(a1, b1);
//// [objectSpreadScenarios.js]
var __assign = (this && this.__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;
};
;
function override(initial, override) {
return __assign({}, initial, override);
}
function update(override) {
this.u = __assign({}, this.u, override);
}
function mixin(one, two) {
return __assign({}, one, two);
}
var a1 = { a: true };
var b1 = { b: 101 };
a1 = override(a1, { a: false });
var host = { u: a1, update: update };
host.update({ a: false });
var mixed = mixin(a1, b1);

View File

@ -0,0 +1,85 @@
=== tests/cases/conformance/types/spread/objectSpreadScenarios.ts ===
interface A1 { a: boolean }
>A1 : Symbol(A1, Decl(objectSpreadScenarios.ts, 0, 0))
>a : Symbol(A1.a, Decl(objectSpreadScenarios.ts, 0, 14))
interface B1 { b: number };
>B1 : Symbol(B1, Decl(objectSpreadScenarios.ts, 0, 27))
>b : Symbol(B1.b, Decl(objectSpreadScenarios.ts, 1, 14))
function override<U>(initial: U, override: U): { ...U, ...U } {
>override : Symbol(override, Decl(objectSpreadScenarios.ts, 1, 27))
>U : Symbol(U, Decl(objectSpreadScenarios.ts, 2, 18))
>initial : Symbol(initial, Decl(objectSpreadScenarios.ts, 2, 21))
>U : Symbol(U, Decl(objectSpreadScenarios.ts, 2, 18))
>override : Symbol(override, Decl(objectSpreadScenarios.ts, 2, 32))
>U : Symbol(U, Decl(objectSpreadScenarios.ts, 2, 18))
>U : Symbol(U, Decl(objectSpreadScenarios.ts, 2, 18))
>U : Symbol(U, Decl(objectSpreadScenarios.ts, 2, 18))
return { ...initial, ...override };
}
function update<U>(this: { u: { ...U } }, override: U): void {
>update : Symbol(update, Decl(objectSpreadScenarios.ts, 4, 1))
>U : Symbol(U, Decl(objectSpreadScenarios.ts, 5, 16))
>this : Symbol(this, Decl(objectSpreadScenarios.ts, 5, 19))
>u : Symbol(u, Decl(objectSpreadScenarios.ts, 5, 26))
>U : Symbol(U, Decl(objectSpreadScenarios.ts, 5, 16))
>override : Symbol(override, Decl(objectSpreadScenarios.ts, 5, 41))
>U : Symbol(U, Decl(objectSpreadScenarios.ts, 5, 16))
this.u = { ...this.u, ...override };
>this.u : Symbol(u, Decl(objectSpreadScenarios.ts, 5, 26))
>this : Symbol(this, Decl(objectSpreadScenarios.ts, 5, 19))
>u : Symbol(u, Decl(objectSpreadScenarios.ts, 5, 26))
>this.u : Symbol(u, Decl(objectSpreadScenarios.ts, 5, 26))
>this : Symbol(this, Decl(objectSpreadScenarios.ts, 5, 19))
>u : Symbol(u, Decl(objectSpreadScenarios.ts, 5, 26))
}
function mixin<T, U>(one: T, two: U): { ...T, ...U } {
>mixin : Symbol(mixin, Decl(objectSpreadScenarios.ts, 7, 1))
>T : Symbol(T, Decl(objectSpreadScenarios.ts, 8, 15))
>U : Symbol(U, Decl(objectSpreadScenarios.ts, 8, 17))
>one : Symbol(one, Decl(objectSpreadScenarios.ts, 8, 21))
>T : Symbol(T, Decl(objectSpreadScenarios.ts, 8, 15))
>two : Symbol(two, Decl(objectSpreadScenarios.ts, 8, 28))
>U : Symbol(U, Decl(objectSpreadScenarios.ts, 8, 17))
>T : Symbol(T, Decl(objectSpreadScenarios.ts, 8, 15))
>U : Symbol(U, Decl(objectSpreadScenarios.ts, 8, 17))
return { ...one, ...two };
}
let a1: A1 = { a: true };
>a1 : Symbol(a1, Decl(objectSpreadScenarios.ts, 11, 3))
>A1 : Symbol(A1, Decl(objectSpreadScenarios.ts, 0, 0))
>a : Symbol(a, Decl(objectSpreadScenarios.ts, 11, 14))
let b1: B1 = { b: 101 };
>b1 : Symbol(b1, Decl(objectSpreadScenarios.ts, 12, 3))
>B1 : Symbol(B1, Decl(objectSpreadScenarios.ts, 0, 27))
>b : Symbol(b, Decl(objectSpreadScenarios.ts, 12, 14))
a1 = override(a1, { a: false });
>a1 : Symbol(a1, Decl(objectSpreadScenarios.ts, 11, 3))
>override : Symbol(override, Decl(objectSpreadScenarios.ts, 1, 27))
>a1 : Symbol(a1, Decl(objectSpreadScenarios.ts, 11, 3))
>a : Symbol(a, Decl(objectSpreadScenarios.ts, 13, 19))
let host = { u: a1, update };
>host : Symbol(host, Decl(objectSpreadScenarios.ts, 14, 3))
>u : Symbol(u, Decl(objectSpreadScenarios.ts, 14, 12))
>a1 : Symbol(a1, Decl(objectSpreadScenarios.ts, 11, 3))
>update : Symbol(update, Decl(objectSpreadScenarios.ts, 14, 19))
host.update({ a: false });
>host.update : Symbol(update, Decl(objectSpreadScenarios.ts, 14, 19))
>host : Symbol(host, Decl(objectSpreadScenarios.ts, 14, 3))
>update : Symbol(update, Decl(objectSpreadScenarios.ts, 14, 19))
>a : Symbol(a, Decl(objectSpreadScenarios.ts, 15, 13))
let mixed = mixin(a1, b1);
>mixed : Symbol(mixed, Decl(objectSpreadScenarios.ts, 16, 3))
>mixin : Symbol(mixin, Decl(objectSpreadScenarios.ts, 7, 1))
>a1 : Symbol(a1, Decl(objectSpreadScenarios.ts, 11, 3))
>b1 : Symbol(b1, Decl(objectSpreadScenarios.ts, 12, 3))

View File

@ -0,0 +1,107 @@
=== tests/cases/conformance/types/spread/objectSpreadScenarios.ts ===
interface A1 { a: boolean }
>A1 : A1
>a : boolean
interface B1 { b: number };
>B1 : B1
>b : number
function override<U>(initial: U, override: U): { ...U, ...U } {
>override : <U>(initial: U, override: U) => { ...U }
>U : U
>initial : U
>U : U
>override : U
>U : U
>U : U
>U : U
return { ...initial, ...override };
>{ ...initial, ...override } : { ...U }
>initial : any
>override : any
}
function update<U>(this: { u: { ...U } }, override: U): void {
>update : <U>(this: { u: { ...U }; }, override: U) => void
>U : U
>this : { u: { ...U }; }
>u : { ...U }
>U : U
>override : U
>U : U
this.u = { ...this.u, ...override };
>this.u = { ...this.u, ...override } : { ...U }
>this.u : { ...U }
>this : { u: { ...U }; }
>u : { ...U }
>{ ...this.u, ...override } : { ...U }
>this.u : { ...U }
>this : { u: { ...U }; }
>u : { ...U }
>override : any
}
function mixin<T, U>(one: T, two: U): { ...T, ...U } {
>mixin : <T, U>(one: T, two: U) => { ...T; ...U }
>T : T
>U : U
>one : T
>T : T
>two : U
>U : U
>T : T
>U : U
return { ...one, ...two };
>{ ...one, ...two } : { ...T; ...U }
>one : any
>two : any
}
let a1: A1 = { a: true };
>a1 : A1
>A1 : A1
>{ a: true } : { a: true; }
>a : boolean
>true : true
let b1: B1 = { b: 101 };
>b1 : B1
>B1 : B1
>{ b: 101 } : { b: number; }
>b : number
>101 : 101
a1 = override(a1, { a: false });
>a1 = override(a1, { a: false }) : { a: boolean; }
>a1 : A1
>override(a1, { a: false }) : { a: boolean; }
>override : <U>(initial: U, override: U) => { ...U }
>a1 : A1
>{ a: false } : { a: false; }
>a : boolean
>false : false
let host = { u: a1, update };
>host : { u: A1; update: <U>(this: { u: { ...U }; }, override: U) => void; }
>{ u: a1, update } : { u: A1; update: <U>(this: { u: { ...U }; }, override: U) => void; }
>u : A1
>a1 : A1
>update : <U>(this: { u: { ...U }; }, override: U) => void
host.update({ a: false });
>host.update({ a: false }) : void
>host.update : <U>(this: { u: { ...U }; }, override: U) => void
>host : { u: A1; update: <U>(this: { u: { ...U }; }, override: U) => void; }
>update : <U>(this: { u: { ...U }; }, override: U) => void
>{ a: false } : { a: false; }
>a : boolean
>false : false
let mixed = mixin(a1, b1);
>mixed : { b: number; a: boolean; }
>mixin(a1, b1) : { b: number; a: boolean; }
>mixin : <T, U>(one: T, two: U) => { ...T; ...U }
>a1 : A1
>b1 : B1

View File

@ -0,0 +1,43 @@
//// [objectSpreadStrictNull.ts]
function f(
definiteBoolean: { sn: boolean },
definiteString: { sn: string },
optionalString: { sn?: string },
optionalNumber: { sn?: number },
undefinedString: { sn: string | undefined },
undefinedNumber: { sn: number | undefined }) {
// optional
let optionalUnionStops: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalNumber };
let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber };
let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber };
// undefined
let undefinedUnionStops: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...undefinedNumber };
let undefinedUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...undefinedString, ...undefinedNumber };
let allUndefined: { sn: string | number | undefined } = { ...undefinedString, ...undefinedNumber };
let undefinedWithOptionalContinues: { sn: string | number | boolean } = { ...definiteBoolean, ...undefinedString, ...optionalNumber };
}
//// [objectSpreadStrictNull.js]
var __assign = (this && this.__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;
};
function f(definiteBoolean, definiteString, optionalString, optionalNumber, undefinedString, undefinedNumber) {
// optional
var optionalUnionStops = __assign({}, definiteBoolean, definiteString, optionalNumber);
var optionalUnionDuplicates = __assign({}, definiteBoolean, definiteString, optionalString, optionalNumber);
var allOptional = __assign({}, optionalString, optionalNumber);
// undefined
var undefinedUnionStops = __assign({}, definiteBoolean, definiteString, undefinedNumber);
var undefinedUnionDuplicates = __assign({}, definiteBoolean, definiteString, undefinedString, undefinedNumber);
var allUndefined = __assign({}, undefinedString, undefinedNumber);
var undefinedWithOptionalContinues = __assign({}, definiteBoolean, undefinedString, optionalNumber);
}

View File

@ -0,0 +1,60 @@
=== tests/cases/conformance/types/spread/objectSpreadStrictNull.ts ===
function f(
>f : Symbol(f, Decl(objectSpreadStrictNull.ts, 0, 0))
definiteBoolean: { sn: boolean },
>definiteBoolean : Symbol(definiteBoolean, Decl(objectSpreadStrictNull.ts, 1, 11))
>sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 2, 22))
definiteString: { sn: string },
>definiteString : Symbol(definiteString, Decl(objectSpreadStrictNull.ts, 2, 37))
>sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 3, 21))
optionalString: { sn?: string },
>optionalString : Symbol(optionalString, Decl(objectSpreadStrictNull.ts, 3, 35))
>sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 4, 21))
optionalNumber: { sn?: number },
>optionalNumber : Symbol(optionalNumber, Decl(objectSpreadStrictNull.ts, 4, 36))
>sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 5, 21))
undefinedString: { sn: string | undefined },
>undefinedString : Symbol(undefinedString, Decl(objectSpreadStrictNull.ts, 5, 36))
>sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 6, 22))
undefinedNumber: { sn: number | undefined }) {
>undefinedNumber : Symbol(undefinedNumber, Decl(objectSpreadStrictNull.ts, 6, 48))
>sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 7, 22))
// optional
let optionalUnionStops: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalNumber };
>optionalUnionStops : Symbol(optionalUnionStops, Decl(objectSpreadStrictNull.ts, 9, 7))
>sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 9, 29))
let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber };
>optionalUnionDuplicates : Symbol(optionalUnionDuplicates, Decl(objectSpreadStrictNull.ts, 10, 7))
>sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 10, 34))
let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber };
>allOptional : Symbol(allOptional, Decl(objectSpreadStrictNull.ts, 11, 7))
>sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 11, 22))
// undefined
let undefinedUnionStops: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...undefinedNumber };
>undefinedUnionStops : Symbol(undefinedUnionStops, Decl(objectSpreadStrictNull.ts, 14, 7))
>sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 14, 30))
let undefinedUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...undefinedString, ...undefinedNumber };
>undefinedUnionDuplicates : Symbol(undefinedUnionDuplicates, Decl(objectSpreadStrictNull.ts, 15, 7))
>sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 15, 35))
let allUndefined: { sn: string | number | undefined } = { ...undefinedString, ...undefinedNumber };
>allUndefined : Symbol(allUndefined, Decl(objectSpreadStrictNull.ts, 16, 7))
>sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 16, 23))
let undefinedWithOptionalContinues: { sn: string | number | boolean } = { ...definiteBoolean, ...undefinedString, ...optionalNumber };
>undefinedWithOptionalContinues : Symbol(undefinedWithOptionalContinues, Decl(objectSpreadStrictNull.ts, 18, 7))
>sn : Symbol(sn, Decl(objectSpreadStrictNull.ts, 18, 41))
}

View File

@ -0,0 +1,88 @@
=== tests/cases/conformance/types/spread/objectSpreadStrictNull.ts ===
function f(
>f : (definiteBoolean: { sn: boolean; }, definiteString: { sn: string; }, optionalString: { sn?: string | undefined; }, optionalNumber: { sn?: number | undefined; }, undefinedString: { sn: string | undefined; }, undefinedNumber: { sn: number | undefined; }) => void
definiteBoolean: { sn: boolean },
>definiteBoolean : { sn: boolean; }
>sn : boolean
definiteString: { sn: string },
>definiteString : { sn: string; }
>sn : string
optionalString: { sn?: string },
>optionalString : { sn?: string | undefined; }
>sn : string | undefined
optionalNumber: { sn?: number },
>optionalNumber : { sn?: number | undefined; }
>sn : number | undefined
undefinedString: { sn: string | undefined },
>undefinedString : { sn: string | undefined; }
>sn : string | undefined
undefinedNumber: { sn: number | undefined }) {
>undefinedNumber : { sn: number | undefined; }
>sn : number | undefined
// optional
let optionalUnionStops: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalNumber };
>optionalUnionStops : { sn: string | number; }
>sn : string | number
>{ ...definiteBoolean, ...definiteString, ...optionalNumber } : { sn: string | number; }
>definiteBoolean : any
>definiteString : any
>optionalNumber : any
let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber };
>optionalUnionDuplicates : { sn: string | number; }
>sn : string | number
>{ ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber } : { sn: string | number; }
>definiteBoolean : any
>definiteString : any
>optionalString : any
>optionalNumber : any
let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber };
>allOptional : { sn?: string | number | undefined; }
>sn : string | number | undefined
>{ ...optionalString, ...optionalNumber } : { sn?: string | number | undefined; }
>optionalString : any
>optionalNumber : any
// undefined
let undefinedUnionStops: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...undefinedNumber };
>undefinedUnionStops : { sn: string | number; }
>sn : string | number
>{ ...definiteBoolean, ...definiteString, ...undefinedNumber } : { sn: string | number; }
>definiteBoolean : any
>definiteString : any
>undefinedNumber : any
let undefinedUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...undefinedString, ...undefinedNumber };
>undefinedUnionDuplicates : { sn: string | number; }
>sn : string | number
>{ ...definiteBoolean, ...definiteString, ...undefinedString, ...undefinedNumber } : { sn: string | number; }
>definiteBoolean : any
>definiteString : any
>undefinedString : any
>undefinedNumber : any
let allUndefined: { sn: string | number | undefined } = { ...undefinedString, ...undefinedNumber };
>allUndefined : { sn: string | number | undefined; }
>sn : string | number | undefined
>{ ...undefinedString, ...undefinedNumber } : { sn: string | number | undefined; }
>undefinedString : any
>undefinedNumber : any
let undefinedWithOptionalContinues: { sn: string | number | boolean } = { ...definiteBoolean, ...undefinedString, ...optionalNumber };
>undefinedWithOptionalContinues : { sn: string | number | boolean; }
>sn : string | number | boolean
>{ ...definiteBoolean, ...undefinedString, ...optionalNumber } : { sn: string | number | boolean; }
>definiteBoolean : any
>undefinedString : any
>optionalNumber : any
}

View File

@ -0,0 +1,52 @@
//// [objectSpreadUnion.ts]
// concrete types work
interface A1 { a: number }
interface A2 { a: string }
let a12: A1 | A2;
let result = { ...a12 };
let sn: number | string = result.a;
let assignable: { ...(A1 | A2) } = result;
function tripleUnion<T, U, V>(t: T, u: U, v: V): void {
let tuv: T | U | V;
let result = { ...tuv, id: 'foo' };
let expected: { ...T, id: string } | { ...U, id: string } | { ...V, id: string } = result;
let assignable: { ...(T | U | V), id: string } = result;
}
function iteratedDoubleUnion<T, U, V>(t: T, u: U, v: V): void {
let tu: T | U;
let uv: U | V;
let result = { ...tu, ...uv, id: 'bar' };
let expected: { ...T, ...U, id: string } | { ...T, ...V, id: string } | { ...U, id: string } | { ...U, ...V, id: string };
let assignable: { ...(T | U), ...(U | V), id: string } = result;
}
//// [objectSpreadUnion.js]
var __assign = (this && this.__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;
};
var a12;
var result = __assign({}, a12);
var sn = result.a;
var assignable = result;
function tripleUnion(t, u, v) {
var tuv;
var result = __assign({}, tuv, { id: 'foo' });
var expected = result;
var assignable = result;
}
function iteratedDoubleUnion(t, u, v) {
var tu;
var uv;
var result = __assign({}, tu, uv, { id: 'bar' });
var expected;
var assignable = result;
}

View File

@ -0,0 +1,122 @@
=== tests/cases/conformance/types/spread/objectSpreadUnion.ts ===
// concrete types work
interface A1 { a: number }
>A1 : Symbol(A1, Decl(objectSpreadUnion.ts, 0, 0))
>a : Symbol(A1.a, Decl(objectSpreadUnion.ts, 1, 14))
interface A2 { a: string }
>A2 : Symbol(A2, Decl(objectSpreadUnion.ts, 1, 26))
>a : Symbol(A2.a, Decl(objectSpreadUnion.ts, 2, 14))
let a12: A1 | A2;
>a12 : Symbol(a12, Decl(objectSpreadUnion.ts, 3, 3))
>A1 : Symbol(A1, Decl(objectSpreadUnion.ts, 0, 0))
>A2 : Symbol(A2, Decl(objectSpreadUnion.ts, 1, 26))
let result = { ...a12 };
>result : Symbol(result, Decl(objectSpreadUnion.ts, 4, 3))
let sn: number | string = result.a;
>sn : Symbol(sn, Decl(objectSpreadUnion.ts, 5, 3))
>result.a : Symbol(a, Decl(objectSpreadUnion.ts, 1, 14), Decl(objectSpreadUnion.ts, 2, 14))
>result : Symbol(result, Decl(objectSpreadUnion.ts, 4, 3))
>a : Symbol(a, Decl(objectSpreadUnion.ts, 1, 14), Decl(objectSpreadUnion.ts, 2, 14))
let assignable: { ...(A1 | A2) } = result;
>assignable : Symbol(assignable, Decl(objectSpreadUnion.ts, 6, 3))
>A1 : Symbol(A1, Decl(objectSpreadUnion.ts, 0, 0))
>A2 : Symbol(A2, Decl(objectSpreadUnion.ts, 1, 26))
>result : Symbol(result, Decl(objectSpreadUnion.ts, 4, 3))
function tripleUnion<T, U, V>(t: T, u: U, v: V): void {
>tripleUnion : Symbol(tripleUnion, Decl(objectSpreadUnion.ts, 6, 42))
>T : Symbol(T, Decl(objectSpreadUnion.ts, 8, 21))
>U : Symbol(U, Decl(objectSpreadUnion.ts, 8, 23))
>V : Symbol(V, Decl(objectSpreadUnion.ts, 8, 26))
>t : Symbol(t, Decl(objectSpreadUnion.ts, 8, 30))
>T : Symbol(T, Decl(objectSpreadUnion.ts, 8, 21))
>u : Symbol(u, Decl(objectSpreadUnion.ts, 8, 35))
>U : Symbol(U, Decl(objectSpreadUnion.ts, 8, 23))
>v : Symbol(v, Decl(objectSpreadUnion.ts, 8, 41))
>V : Symbol(V, Decl(objectSpreadUnion.ts, 8, 26))
let tuv: T | U | V;
>tuv : Symbol(tuv, Decl(objectSpreadUnion.ts, 9, 7))
>T : Symbol(T, Decl(objectSpreadUnion.ts, 8, 21))
>U : Symbol(U, Decl(objectSpreadUnion.ts, 8, 23))
>V : Symbol(V, Decl(objectSpreadUnion.ts, 8, 26))
let result = { ...tuv, id: 'foo' };
>result : Symbol(result, Decl(objectSpreadUnion.ts, 10, 7))
>id : Symbol(id, Decl(objectSpreadUnion.ts, 10, 26))
let expected: { ...T, id: string } | { ...U, id: string } | { ...V, id: string } = result;
>expected : Symbol(expected, Decl(objectSpreadUnion.ts, 11, 7))
>T : Symbol(T, Decl(objectSpreadUnion.ts, 8, 21))
>id : Symbol(id, Decl(objectSpreadUnion.ts, 11, 25))
>U : Symbol(U, Decl(objectSpreadUnion.ts, 8, 23))
>id : Symbol(id, Decl(objectSpreadUnion.ts, 11, 48))
>V : Symbol(V, Decl(objectSpreadUnion.ts, 8, 26))
>id : Symbol(id, Decl(objectSpreadUnion.ts, 11, 71))
>result : Symbol(result, Decl(objectSpreadUnion.ts, 10, 7))
let assignable: { ...(T | U | V), id: string } = result;
>assignable : Symbol(assignable, Decl(objectSpreadUnion.ts, 12, 7))
>T : Symbol(T, Decl(objectSpreadUnion.ts, 8, 21))
>U : Symbol(U, Decl(objectSpreadUnion.ts, 8, 23))
>V : Symbol(V, Decl(objectSpreadUnion.ts, 8, 26))
>id : Symbol(id, Decl(objectSpreadUnion.ts, 12, 37))
>result : Symbol(result, Decl(objectSpreadUnion.ts, 10, 7))
}
function iteratedDoubleUnion<T, U, V>(t: T, u: U, v: V): void {
>iteratedDoubleUnion : Symbol(iteratedDoubleUnion, Decl(objectSpreadUnion.ts, 13, 1))
>T : Symbol(T, Decl(objectSpreadUnion.ts, 14, 29))
>U : Symbol(U, Decl(objectSpreadUnion.ts, 14, 31))
>V : Symbol(V, Decl(objectSpreadUnion.ts, 14, 34))
>t : Symbol(t, Decl(objectSpreadUnion.ts, 14, 38))
>T : Symbol(T, Decl(objectSpreadUnion.ts, 14, 29))
>u : Symbol(u, Decl(objectSpreadUnion.ts, 14, 43))
>U : Symbol(U, Decl(objectSpreadUnion.ts, 14, 31))
>v : Symbol(v, Decl(objectSpreadUnion.ts, 14, 49))
>V : Symbol(V, Decl(objectSpreadUnion.ts, 14, 34))
let tu: T | U;
>tu : Symbol(tu, Decl(objectSpreadUnion.ts, 15, 7))
>T : Symbol(T, Decl(objectSpreadUnion.ts, 14, 29))
>U : Symbol(U, Decl(objectSpreadUnion.ts, 14, 31))
let uv: U | V;
>uv : Symbol(uv, Decl(objectSpreadUnion.ts, 16, 7))
>U : Symbol(U, Decl(objectSpreadUnion.ts, 14, 31))
>V : Symbol(V, Decl(objectSpreadUnion.ts, 14, 34))
let result = { ...tu, ...uv, id: 'bar' };
>result : Symbol(result, Decl(objectSpreadUnion.ts, 17, 7))
>id : Symbol(id, Decl(objectSpreadUnion.ts, 17, 32))
let expected: { ...T, ...U, id: string } | { ...T, ...V, id: string } | { ...U, id: string } | { ...U, ...V, id: string };
>expected : Symbol(expected, Decl(objectSpreadUnion.ts, 18, 7))
>T : Symbol(T, Decl(objectSpreadUnion.ts, 14, 29))
>U : Symbol(U, Decl(objectSpreadUnion.ts, 14, 31))
>id : Symbol(id, Decl(objectSpreadUnion.ts, 18, 31))
>T : Symbol(T, Decl(objectSpreadUnion.ts, 14, 29))
>V : Symbol(V, Decl(objectSpreadUnion.ts, 14, 34))
>id : Symbol(id, Decl(objectSpreadUnion.ts, 18, 60))
>U : Symbol(U, Decl(objectSpreadUnion.ts, 14, 31))
>id : Symbol(id, Decl(objectSpreadUnion.ts, 18, 83))
>U : Symbol(U, Decl(objectSpreadUnion.ts, 14, 31))
>V : Symbol(V, Decl(objectSpreadUnion.ts, 14, 34))
>id : Symbol(id, Decl(objectSpreadUnion.ts, 18, 112))
let assignable: { ...(T | U), ...(U | V), id: string } = result;
>assignable : Symbol(assignable, Decl(objectSpreadUnion.ts, 19, 7))
>T : Symbol(T, Decl(objectSpreadUnion.ts, 14, 29))
>U : Symbol(U, Decl(objectSpreadUnion.ts, 14, 31))
>U : Symbol(U, Decl(objectSpreadUnion.ts, 14, 31))
>V : Symbol(V, Decl(objectSpreadUnion.ts, 14, 34))
>id : Symbol(id, Decl(objectSpreadUnion.ts, 19, 45))
>result : Symbol(result, Decl(objectSpreadUnion.ts, 17, 7))
}

View File

@ -0,0 +1,131 @@
=== tests/cases/conformance/types/spread/objectSpreadUnion.ts ===
// concrete types work
interface A1 { a: number }
>A1 : A1
>a : number
interface A2 { a: string }
>A2 : A2
>a : string
let a12: A1 | A2;
>a12 : A1 | A2
>A1 : A1
>A2 : A2
let result = { ...a12 };
>result : { a: number; } | { a: string; }
>{ ...a12 } : { a: number; } | { a: string; }
>a12 : any
let sn: number | string = result.a;
>sn : string | number
>result.a : string | number
>result : { a: number; } | { a: string; }
>a : string | number
let assignable: { ...(A1 | A2) } = result;
>assignable : { a: number; } | { a: string; }
>A1 : A1
>A2 : A2
>result : { a: number; } | { a: string; }
function tripleUnion<T, U, V>(t: T, u: U, v: V): void {
>tripleUnion : <T, U, V>(t: T, u: U, v: V) => void
>T : T
>U : U
>V : V
>t : T
>T : T
>u : U
>U : U
>v : V
>V : V
let tuv: T | U | V;
>tuv : T | U | V
>T : T
>U : U
>V : V
let result = { ...tuv, id: 'foo' };
>result : { ...T; id: string; } | { ...U; id: string; } | { ...V; id: string; }
>{ ...tuv, id: 'foo' } : { ...T; id: string; } | { ...U; id: string; } | { ...V; id: string; }
>tuv : any
>id : string
>'foo' : "foo"
let expected: { ...T, id: string } | { ...U, id: string } | { ...V, id: string } = result;
>expected : { ...T; id: string; } | { ...U; id: string; } | { ...V; id: string; }
>T : T
>id : string
>U : U
>id : string
>V : V
>id : string
>result : { ...T; id: string; } | { ...U; id: string; } | { ...V; id: string; }
let assignable: { ...(T | U | V), id: string } = result;
>assignable : { ...T; id: string; } | { ...U; id: string; } | { ...V; id: string; }
>T : T
>U : U
>V : V
>id : string
>result : { ...T; id: string; } | { ...U; id: string; } | { ...V; id: string; }
}
function iteratedDoubleUnion<T, U, V>(t: T, u: U, v: V): void {
>iteratedDoubleUnion : <T, U, V>(t: T, u: U, v: V) => void
>T : T
>U : U
>V : V
>t : T
>T : T
>u : U
>U : U
>v : V
>V : V
let tu: T | U;
>tu : T | U
>T : T
>U : U
let uv: U | V;
>uv : U | V
>U : U
>V : V
let result = { ...tu, ...uv, id: 'bar' };
>result : { ...U; id: string; } | { ...T; ...U; id: string; } | { ...T; ...V; id: string; } | { ...U; ...V; id: string; }
>{ ...tu, ...uv, id: 'bar' } : { ...U; id: string; } | { ...T; ...U; id: string; } | { ...T; ...V; id: string; } | { ...U; ...V; id: string; }
>tu : any
>uv : any
>id : string
>'bar' : "bar"
let expected: { ...T, ...U, id: string } | { ...T, ...V, id: string } | { ...U, id: string } | { ...U, ...V, id: string };
>expected : { ...T; ...U; id: string; } | { ...T; ...V; id: string; } | { ...U; id: string; } | { ...U; ...V; id: string; }
>T : T
>U : U
>id : string
>T : T
>V : V
>id : string
>U : U
>id : string
>U : U
>V : V
>id : string
let assignable: { ...(T | U), ...(U | V), id: string } = result;
>assignable : { ...U; id: string; } | { ...T; ...U; id: string; } | { ...T; ...V; id: string; } | { ...U; ...V; id: string; }
>T : T
>U : U
>U : U
>V : V
>id : string
>result : { ...U; id: string; } | { ...T; ...U; id: string; } | { ...T; ...V; id: string; } | { ...U; ...V; id: string; }
}

View File

@ -1,12 +1,12 @@
tests/cases/conformance/es6/destructuring/restElementMustBeLast.ts(1,9): error TS2462: A rest element must be last in an array destructuring pattern
tests/cases/conformance/es6/destructuring/restElementMustBeLast.ts(2,2): error TS2462: A rest element must be last in an array destructuring pattern
tests/cases/conformance/types/rest/restElementMustBeLast.ts(1,9): error TS2462: A rest element must be last in a destructuring pattern
tests/cases/conformance/types/rest/restElementMustBeLast.ts(2,2): error TS2462: A rest element must be last in a destructuring pattern
==== tests/cases/conformance/es6/destructuring/restElementMustBeLast.ts (2 errors) ====
==== tests/cases/conformance/types/rest/restElementMustBeLast.ts (2 errors) ====
var [...a, x] = [1, 2, 3]; // Error, rest must be last element
~
!!! error TS2462: A rest element must be last in an array destructuring pattern
!!! error TS2462: A rest element must be last in a destructuring pattern
[...a, x] = [1, 2, 3]; // Error, rest must be last element
~~~~
!!! error TS2462: A rest element must be last in an array destructuring pattern
!!! error TS2462: A rest element must be last in a destructuring pattern

View File

@ -194,13 +194,13 @@ for (_b = getRobot(), _c = _b.name, nameA = _c === void 0 ? "noName" : _c, _b, i
for (_d = { name: "trimmer", skill: "trimming" }, _e = _d.name, nameA = _e === void 0 ? "noName" : _e, _d, i = 0; i < 1; i++) {
console.log(nameA);
}
for (_f = multiRobot.skills, _g = _f === void 0 ? { primary: "none", secondary: "none" } : _f, _h = _g.primary, primaryA = _h === void 0 ? "primary" : _h, _j = _g.secondary, secondaryA = _j === void 0 ? "secondary" : _j, multiRobot, i = 0; i < 1; i++) {
for (_f = multiRobot.skills, _g = _f === void 0 ? { primary: "none", secondary: "none" } : _f, _h = _g.primary, primaryA = _h === void 0 ? "primary" : _h, _j = _g.secondary, secondaryA = _j === void 0 ? "secondary" : _j, multiRobot, multiRobot, i = 0; i < 1; i++) {
console.log(primaryA);
}
for (_k = getMultiRobot(), _l = _k.skills, _m = _l === void 0 ? { primary: "none", secondary: "none" } : _l, _o = _m.primary, primaryA = _o === void 0 ? "primary" : _o, _p = _m.secondary, secondaryA = _p === void 0 ? "secondary" : _p, _k, i = 0; i < 1; i++) {
for (_k = getMultiRobot(), (_l = _k.skills, _m = _l === void 0 ? { primary: "none", secondary: "none" } : _l, _o = _m.primary, primaryA = _o === void 0 ? "primary" : _o, _p = _m.secondary, secondaryA = _p === void 0 ? "secondary" : _p, _k), _k, i = 0; i < 1; i++) {
console.log(primaryA);
}
for (_q = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, _r = _q.skills, _s = _r === void 0 ? { primary: "none", secondary: "none" } : _r, _t = _s.primary, primaryA = _t === void 0 ? "primary" : _t, _u = _s.secondary, secondaryA = _u === void 0 ? "secondary" : _u, _q,
for (_q = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, (_r = _q.skills, _s = _r === void 0 ? { primary: "none", secondary: "none" } : _r, _t = _s.primary, primaryA = _t === void 0 ? "primary" : _t, _u = _s.secondary, secondaryA = _u === void 0 ? "secondary" : _u, _q), _q,
i = 0; i < 1; i++) {
console.log(primaryA);
}
@ -213,13 +213,13 @@ for (_w = getRobot(), _x = _w.name, name = _x === void 0 ? "noName" : _x, _w, i
for (_y = { name: "trimmer", skill: "trimming" }, _z = _y.name, name = _z === void 0 ? "noName" : _z, _y, i = 0; i < 1; i++) {
console.log(nameA);
}
for (_0 = multiRobot.skills, _1 = _0 === void 0 ? { primary: "none", secondary: "none" } : _0, _2 = _1.primary, primary = _2 === void 0 ? "primary" : _2, _3 = _1.secondary, secondary = _3 === void 0 ? "secondary" : _3, multiRobot, i = 0; i < 1; i++) {
for (_0 = multiRobot.skills, _1 = _0 === void 0 ? { primary: "none", secondary: "none" } : _0, _2 = _1.primary, primary = _2 === void 0 ? "primary" : _2, _3 = _1.secondary, secondary = _3 === void 0 ? "secondary" : _3, multiRobot, multiRobot, i = 0; i < 1; i++) {
console.log(primaryA);
}
for (_4 = getMultiRobot(), _5 = _4.skills, _6 = _5 === void 0 ? { primary: "none", secondary: "none" } : _5, _7 = _6.primary, primary = _7 === void 0 ? "primary" : _7, _8 = _6.secondary, secondary = _8 === void 0 ? "secondary" : _8, _4, i = 0; i < 1; i++) {
for (_4 = getMultiRobot(), (_5 = _4.skills, _6 = _5 === void 0 ? { primary: "none", secondary: "none" } : _5, _7 = _6.primary, primary = _7 === void 0 ? "primary" : _7, _8 = _6.secondary, secondary = _8 === void 0 ? "secondary" : _8, _4), _4, i = 0; i < 1; i++) {
console.log(primaryA);
}
for (_9 = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, _10 = _9.skills, _11 = _10 === void 0 ? { primary: "none", secondary: "none" } : _10, _12 = _11.primary, primary = _12 === void 0 ? "primary" : _12, _13 = _11.secondary, secondary = _13 === void 0 ? "secondary" : _13, _9,
for (_9 = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, (_10 = _9.skills, _11 = _10 === void 0 ? { primary: "none", secondary: "none" } : _10, _12 = _11.primary, primary = _12 === void 0 ? "primary" : _12, _13 = _11.secondary, secondary = _13 === void 0 ? "secondary" : _13, _9), _9,
i = 0; i < 1; i++) {
console.log(primaryA);
}
@ -232,13 +232,13 @@ for (_16 = getRobot(), _17 = _16.name, nameA = _17 === void 0 ? "noName" : _17,
for (_19 = { name: "trimmer", skill: "trimming" }, _20 = _19.name, nameA = _20 === void 0 ? "noName" : _20, _21 = _19.skill, skillA = _21 === void 0 ? "skill" : _21, _19, i = 0; i < 1; i++) {
console.log(nameA);
}
for (_22 = multiRobot.name, nameA = _22 === void 0 ? "noName" : _22, _23 = multiRobot.skills, _24 = _23 === void 0 ? { primary: "none", secondary: "none" } : _23, _25 = _24.primary, primaryA = _25 === void 0 ? "primary" : _25, _26 = _24.secondary, secondaryA = _26 === void 0 ? "secondary" : _26, multiRobot, i = 0; i < 1; i++) {
for (_22 = multiRobot.name, nameA = _22 === void 0 ? "noName" : _22, _23 = multiRobot.skills, _24 = _23 === void 0 ? { primary: "none", secondary: "none" } : _23, _25 = _24.primary, primaryA = _25 === void 0 ? "primary" : _25, _26 = _24.secondary, secondaryA = _26 === void 0 ? "secondary" : _26, multiRobot, multiRobot, i = 0; i < 1; i++) {
console.log(primaryA);
}
for (_27 = getMultiRobot(), _28 = _27.name, nameA = _28 === void 0 ? "noName" : _28, _29 = _27.skills, _30 = _29 === void 0 ? { primary: "none", secondary: "none" } : _29, _31 = _30.primary, primaryA = _31 === void 0 ? "primary" : _31, _32 = _30.secondary, secondaryA = _32 === void 0 ? "secondary" : _32, _27, i = 0; i < 1; i++) {
for (_27 = getMultiRobot(), (_28 = _27.name, nameA = _28 === void 0 ? "noName" : _28, _29 = _27.skills, _30 = _29 === void 0 ? { primary: "none", secondary: "none" } : _29, _31 = _30.primary, primaryA = _31 === void 0 ? "primary" : _31, _32 = _30.secondary, secondaryA = _32 === void 0 ? "secondary" : _32, _27), _27, i = 0; i < 1; i++) {
console.log(primaryA);
}
for (_33 = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, _34 = _33.name, nameA = _34 === void 0 ? "noName" : _34, _35 = _33.skills, _36 = _35 === void 0 ? { primary: "none", secondary: "none" } : _35, _37 = _36.primary, primaryA = _37 === void 0 ? "primary" : _37, _38 = _36.secondary, secondaryA = _38 === void 0 ? "secondary" : _38, _33,
for (_33 = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, (_34 = _33.name, nameA = _34 === void 0 ? "noName" : _34, _35 = _33.skills, _36 = _35 === void 0 ? { primary: "none", secondary: "none" } : _35, _37 = _36.primary, primaryA = _37 === void 0 ? "primary" : _37, _38 = _36.secondary, secondaryA = _38 === void 0 ? "secondary" : _38, _33), _33,
i = 0; i < 1; i++) {
console.log(primaryA);
}
@ -251,15 +251,16 @@ for (_41 = getRobot(), _42 = _41.name, name = _42 === void 0 ? "noName" : _42, _
for (_44 = { name: "trimmer", skill: "trimming" }, _45 = _44.name, name = _45 === void 0 ? "noName" : _45, _46 = _44.skill, skill = _46 === void 0 ? "skill" : _46, _44, i = 0; i < 1; i++) {
console.log(nameA);
}
for (_47 = multiRobot.name, name = _47 === void 0 ? "noName" : _47, _48 = multiRobot.skills, _49 = _48 === void 0 ? { primary: "none", secondary: "none" } : _48, _50 = _49.primary, primary = _50 === void 0 ? "primary" : _50, _51 = _49.secondary, secondary = _51 === void 0 ? "secondary" : _51, multiRobot, i = 0; i < 1; i++) {
for (_47 = multiRobot.name, name = _47 === void 0 ? "noName" : _47, _48 = multiRobot.skills, _49 = _48 === void 0 ? { primary: "none", secondary: "none" } : _48, _50 = _49.primary, primary = _50 === void 0 ? "primary" : _50, _51 = _49.secondary, secondary = _51 === void 0 ? "secondary" : _51, multiRobot, multiRobot, i = 0; i < 1; i++) {
console.log(primaryA);
}
for (_52 = getMultiRobot(), _53 = _52.name, name = _53 === void 0 ? "noName" : _53, _54 = _52.skills, _55 = _54 === void 0 ? { primary: "none", secondary: "none" } : _54, _56 = _55.primary, primary = _56 === void 0 ? "primary" : _56, _57 = _55.secondary, secondary = _57 === void 0 ? "secondary" : _57, _52, i = 0; i < 1; i++) {
for (_52 = getMultiRobot(), (_53 = _52.name, name = _53 === void 0 ? "noName" : _53, _54 = _52.skills, _55 = _54 === void 0 ? { primary: "none", secondary: "none" } : _54, _56 = _55.primary, primary = _56 === void 0 ? "primary" : _56, _57 = _55.secondary, secondary = _57 === void 0 ? "secondary" : _57, _52), _52, i = 0; i < 1; i++) {
console.log(primaryA);
}
for (_58 = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, _59 = _58.name, name = _59 === void 0 ? "noName" : _59, _60 = _58.skills, _61 = _60 === void 0 ? { primary: "none", secondary: "none" } : _60, _62 = _61.primary, primary = _62 === void 0 ? "primary" : _62, _63 = _61.secondary, secondary = _63 === void 0 ? "secondary" : _63, _58,
for (_58 = { name: "trimmer", skills: { primary: "trimming", secondary: "edging" } }, (_59 = _58.name, name = _59 === void 0 ? "noName" : _59, _60 = _58.skills, _61 = _60 === void 0 ? { primary: "none", secondary: "none" } : _60, _62 = _61.primary, primary = _62 === void 0 ? "primary" : _62, _63 = _61.secondary, secondary = _63 === void 0 ? "secondary" : _63, _58), _58,
i = 0; i < 1; i++) {
console.log(primaryA);
}
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63;
var _k, _q, _4, _9, _27, _33, _52, _58;
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _l, _m, _o, _p, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _5, _6, _7, _8, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _28, _29, _30, _31, _32, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _53, _54, _55, _56, _57, _59, _60, _61, _62, _63;
//# sourceMappingURL=sourceMapValidationDestructuringForObjectBindingPatternDefaultValues2.js.map

View File

@ -3,8 +3,5 @@ var {h?} = { h?: 1 };
var {i}: string | number = { i: 2 };
var {i1}: string | number| {} = { i1: 2 };
var { f2: {f21} = { f212: "string" } }: any = undefined;
var { ...d1 } = {
a: 1, b: 1, d1: 9, e: 10
}
var {1} = { 1 };
var {"prop"} = { "prop": 1 };
var {"prop"} = { "prop": 1 };

View File

@ -0,0 +1,33 @@
// @target: es2015
let o = { a: 1, b: 'no' }
var { ...clone } = o;
var { a, ...justB } = o;
var { a, b: renamed, ...empty } = o;
var { ['b']: renamed, ...justA } = o;
var { 'b': renamed, ...justA } = o;
var { b: { '0': n, '1': oooo }, ...justA } = o;
let o2 = { c: 'terrible idea?', d: 'yes' };
var { d: renamed, ...d } = o2;
let nestedrest: { x: number, n1: { y: number, n2: { z: number, n3: { n4: number } } }, rest: number, restrest: number };
var { x, n1: { y, n2: { z, n3: { ...nr } } }, ...restrest } = nestedrest;
let complex: { x: { ka, ki }, y: number };
var { x: { ka, ...nested }, y: other, ...rest } = complex;
({x: { ka, ...nested }, y: other, ...rest} = complex);
var { x, ...fresh } = { x: 1, y: 2 };
({ x, ...fresh } = { x: 1, y: 2 });
class Removable {
private x: number;
protected y: number;
set z(value: number) { }
get both(): number { return 12 }
set both(value: number) { }
m() { }
removed: string;
remainder: string;
}
var removable = new Removable();
var { removed, ...removableRest } = removable;

View File

@ -0,0 +1,14 @@
// @target: es2015
let ka: any;
let nested: { ki };
let other: number;
let rest: { };
let complex: { x: { ka, ki }, y: number };
({x: { ka, ...nested }, y: other, ...rest} = complex);
// should be:
let overEmit: { a: { ka: string, x: string }[], b: { z: string, ki: string, ku: string }, ke: string, ko: string };
// var _g = overEmit.a, [_h, ...y] = _g, nested2 = __rest(_h, []), _j = overEmit.b, { z } = _j, c = __rest(_j, ["z"]), rest2 = __rest(overEmit, ["a", "b"]);
var { a: [{ ...nested2 }, ...y], b: { z, ...c }, ...rest2 } = overEmit;
({ a: [{ ...nested2 }, ...y], b: { z, ...c }, ...rest2 } = overEmit);

View File

@ -0,0 +1,14 @@
// @target: es2015
let array: { x: number, y: string }[];
for (let { x, ...restOf } of array) {
[x, restOf];
}
let xx: number;
let rrestOff: { y: string };
for ({ x: xx, ...rrestOff } of array ) {
[xx, rrestOff];
}
for (const norest of array.map(a => ({ ...a, x: 'a string' }))) {
[norest.x, norest.y];
// x is now a string. who knows why.
}

View File

@ -0,0 +1,8 @@
let o = { a: 1, b: 'no' };
var { ...mustBeLast, a } = o;
function stillMustBeLast({ ...mustBeLast, a }: { a: number, b: string }): void {
}
function generic<T extends { x, y }>(t: T) {
let { x, ...rest } = t;
return rest;
}

View File

@ -0,0 +1,8 @@
// @target: es2015
function cloneAgain({ a, ...clone }: { a: number, b: string }): void {
}
declare function suddenly(f: (a: { x: { z, ka }, y: string }) => void);
suddenly(({ x: a, ...rest }) => rest.y);
suddenly(({ x: { z = 12, ...nested }, ...rest } = { x: { z: 1, ka: 1 }, y: 'noo' }) => rest.y + nested.ka);

View File

@ -0,0 +1,81 @@
// @target: es5
let o = { a: 1, b: 'no' }
let o2 = { b: 'yes', c: true }
let swap = { a: 'yes', b: -1 };
let addAfter: { a: number, b: string, c: boolean } =
{ ...o, c: false }
let addBefore: { a: number, b: string, c: boolean } =
{ c: false, ...o }
// Note: ignore still changes the order that properties are printed
let ignore: { a: number, b: string } =
{ b: 'ignored', ...o }
let override: { a: number, b: string } =
{ ...o, b: 'override' }
let nested: { a: number, b: boolean, c: string } =
{ ...{ a: 3, ...{ b: false, c: 'overriden' } }, c: 'whatever' }
let combined: { a: number, b: string, c: boolean } =
{ ...o, ...o2 }
let combinedBefore: { a: number, b: string, c: boolean } =
{ b: 'ok', ...o, ...o2 }
let combinedMid: { a: number, b: string, c: boolean } =
{ ...o, b: 'ok', ...o2 }
let combinedAfter: { a: number, b: string, c: boolean } =
{ ...o, ...o2, b: 'ok' }
let combinedNested: { a: number, b: boolean, c: string, d: string } =
{ ...{ a: 4, ...{ b: false, c: 'overriden' } }, d: 'actually new', ...{ a: 5, d: 'maybe new' } }
let combinedNestedChangeType: { a: number, b: boolean, c: number } =
{ ...{ a: 1, ...{ b: false, c: 'overriden' } }, c: -1 }
let propertyNested: { a: { a: number, b: string } } =
{ a: { ... o } }
// accessors don't copy the descriptor
// (which means that readonly getters become read/write properties)
let op = { get a () { return 6 } };
let getter: { a: number, c: number } =
{ ...op, c: 7 }
getter.a = 12;
// functions result in { }
let spreadFunc = { ...(function () { }) };
// any results in any
let anything: any;
let spreadAny = { ...anything };
// methods are not enumerable
class C { p = 1; m() { } }
let c: C = new C()
let spreadC: { p: number } = { ...c }
// own methods are enumerable
let cplus: { p: number, plus(): void } = { ...c, plus() { return this.p + 1; } };
cplus.plus();
// new field's type conflicting with existing field is OK
let changeTypeAfter: { a: string, b: string } =
{ ...o, a: 'wrong type?' }
let changeTypeBefore: { a: number, b: string } =
{ a: 'wrong type?', ...o };
let changeTypeBoth: { a: string, b: number } =
{ ...o, ...swap };
// optional
let definiteBoolean: { sn: boolean };
let definiteString: { sn: string };
let optionalString: { sn?: string };
let optionalNumber: { sn?: number };
let optionalUnionStops: { sn: string | number | boolean } = { ...definiteBoolean, ...definiteString, ...optionalNumber };
let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber };
let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber };
// computed property
let computedFirst: { a: number, b: string, "before everything": number } =
{ ['before everything']: 12, ...o, b: 'yes' }
let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } =
{ ...o, ['in the middle']: 13, b: 'maybe?', ...o2 }
let computedAfter: { a: number, b: string, "at the end": number } =
{ ...o, b: 'yeah', ['at the end']: 14 }
// shortcut syntax
let a = 12;
let shortCutted: { a: number, b: string } = { ...o, a }

View File

@ -0,0 +1,16 @@
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 };
// only indexed has indexer, so i[101]: any
i[101];
let ii = { ...indexed, ...indexed2 };
// both have indexer, so i[1001]: number | boolean
ii[1001];

View File

@ -0,0 +1,71 @@
// @target: es5
let o = { a: 1, b: 'no' }
/// private propagates
class PrivateOptionalX {
private x?: number;
}
class PublicX {
public x: number;
}
let publicX: PublicX;
let privateOptionalX: PrivateOptionalX;
let o2 = { ...publicX, ...privateOptionalX };
let sn: number = o2.x; // error, x is private
let optionalString: { sn?: string };
let optionalNumber: { sn?: number };
let allOptional: { sn: string | number } = { ...optionalString, ...optionalNumber };
// error, 'sn' is optional in source, required in target
// assignability as target
interface Bool { b: boolean };
interface Str { s: string };
let spread = { ...{ b: true }, ...{s: "foo" } };
spread = { s: "foo" }; // error, missing 'b'
let b = { b: false };
spread = b; // error, missing 's'
// literal repeats are not allowed, but spread repeats are fine
let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' }
let duplicatedSpread = { ...o, ...o }
// null, undefined and primitives are not allowed
let spreadNull = { ...null };
let spreadUndefind = { ...undefined };
let spreadNum = { ...12 };
let spreadSum = { ...1 + 1 };
spreadSum.toFixed(); // error, no methods from number
let spreadBool = { ...false };
spreadBool.valueOf(); // error, what were you thinking?
let spreadStr = { ...'foo' };
spreadStr.length; // error, no 'length'
spreadStr.charAt(1); // error, no methods either
// functions are skipped
let spreadFunc = { ...function () { } }
spreadFunc(); // error, no call signature
// write-only properties get skipped
let setterOnly = { ...{ set b (bad: number) { } } };
setterOnly.b = 12; // error, 'b' does not exist
// methods are skipped because they aren't enumerable
class C { p = 1; m() { } }
let c: C = new C()
let spreadC = { ...c }
spreadC.m(); // error 'm' is not in '{ ... c }'
// generics
function f<T, U>(t: T, u: U) {
return { ...t, ...u, id: 'id' };
}
function override<U>(initial: U, override: U): U {
return { ...initial, ...override };
}
let exclusive: { id: string, a: number, b: string, c: string, d: boolean } =
f({ a: 1, b: 'yes' }, { c: 'no', d: false })
let overlap: { id: string, a: number, b: string } =
f({ a: 1 }, { a: 2, b: 'extra' })
let overlapConflict: { id:string, a: string } =
f({ a: 1 }, { a: 'mismatch' })
let overwriteId: { id: string, a: number, c: number, d: string } =
f({ a: 1, id: true }, { c: 1, d: 'no' })

View File

@ -0,0 +1,4 @@
let o7 = { ...o? };
let o8 = { ...*o };
let o9 = { ...matchMedia() { }};
let o10 = { ...get x() { return 12; }};

View File

@ -0,0 +1,6 @@
// @target: esnext
const y = { a: 'yes', b: 'no' };
const o = { x: 1, ...y };
var b;
var rest;
({ b, ...rest } = o);

View File

@ -0,0 +1,21 @@
// @strictNullChecks: true
function f(
definiteBoolean: { sn: boolean },
definiteString: { sn: string },
optionalString: { sn?: string },
optionalNumber: { sn?: number },
undefinedString: { sn: string | undefined },
undefinedNumber: { sn: number | undefined }) {
// optional
let optionalUnionStops: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalNumber };
let optionalUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...optionalString, ...optionalNumber };
let allOptional: { sn?: string | number } = { ...optionalString, ...optionalNumber };
// undefined
let undefinedUnionStops: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...undefinedNumber };
let undefinedUnionDuplicates: { sn: string | number } = { ...definiteBoolean, ...definiteString, ...undefinedString, ...undefinedNumber };
let allUndefined: { sn: string | number | undefined } = { ...undefinedString, ...undefinedNumber };
let undefinedWithOptionalContinues: { sn: string | number | boolean } = { ...definiteBoolean, ...undefinedString, ...optionalNumber };
}

View File

@ -0,0 +1,35 @@
/// <reference path='fourslash.ts'/>
////let o = { a: 1, b: 'no' }
////let o2 = { b: 'yes', c: true }
////let swap = { a: 'yes', b: -1 };
////let addAfter: { a: number, b: string, c: boolean } =
//// { ...o, c: false }
////let addBefore: { a: number, b: string, c: boolean } =
//// { c: false, ...o }
////let ignore: { a: number, b: string } =
//// { b: 'ignored', ...o }
////ignore./*1*/a;
////let combinedNestedChangeType: { a: number, b: boolean, c: number } =
//// { ...{ a: 1, ...{ b: false, c: 'overriden' } }, c: -1 }
////combinedNestedChangeType./*2*/a;
////let spreadNull: { a: number } =
//// { a: 7, ...null }
////let spreadUndefined: { a: number } =
//// { a: 7, ...undefined }
////spreadNull./*3*/a;
////spreadUndefined./*4*/a;
goTo.marker('1');
verify.memberListContains('a', '(property) a: number');
verify.memberListContains('b', '(property) b: string');
verify.memberListCount(2);
goTo.marker('2');
verify.memberListContains('a', '(property) a: number');
verify.memberListContains('b', '(property) b: boolean');
verify.memberListContains('c', '(property) c: number');
verify.memberListCount(3);
goTo.marker('3');
verify.memberListContains('a', '(property) a: number');
verify.memberListCount(1);
goTo.marker('4');
verify.memberListContains('a', '(property) a: number');
verify.memberListCount(1);

View File

@ -0,0 +1,13 @@
/// <reference path='fourslash.ts'/>
////interface Gen {
//// x: number;
//// parent: Gen;
//// millenial: string;
////}
////let t: Gen;
////var { x, ...rest } = t;
////rest./*1*/x;
goTo.marker('1');
verify.memberListContains('parent', '(property) Gen.parent: Gen');
verify.memberListContains('millenial', '(property) Gen.millenial: string');
verify.memberListCount(2);

View File

@ -0,0 +1,14 @@
/// <reference path='fourslash.ts'/>
////interface A1 { [|a|]: string };
////interface A2 { [|a|]?: number };
////let a1: A1;
////let a2: A2;
////let a12 = { ...a1, ...a2 };
////a12.[|a|];
const ranges = test.ranges();
// members of spread types only refer to themselves and the resulting property
verify.referencesOf(ranges[0], [ranges[0], ranges[2]]);
verify.referencesOf(ranges[1], [ranges[1], ranges[2]]);
// but the resulting property refers to everything
verify.referencesOf(ranges[2], ranges);

View File

@ -0,0 +1,12 @@
/// <reference path='fourslash.ts'/>
////interface Gen {
//// x: number
//// [|parent|]: Gen;
//// millenial: string;
////}
////let t: Gen;
////var { x, ...rest } = t;
////rest.[|parent|];
const ranges = test.ranges();
verify.referencesOf(ranges[0], ranges);
verify.referencesOf(ranges[1], ranges);

View File

@ -0,0 +1,9 @@
/// <reference path='fourslash.ts'/>
////interface A1 { /*1*/a: number };
////interface A2 { /*2*/a?: number };
////let a1: A1;
////let a2: A2;
////let a12 = { ...a1, ...a2 };
////a12.a/*3*/;
verify.goToDefinition('3', [ '1', '2' ]);

View File

@ -0,0 +1,12 @@
/// <reference path='fourslash.ts'/>
////interface Gen {
//// x: number;
//// /*1*/parent: Gen;
//// millenial: string;
////}
////let t: Gen;
////var { x, ...rest } = t;
////rest./*2*/parent;
const ranges = test.ranges();
verify.goToDefinition('2', [ '1' ]);

View File

@ -0,0 +1,20 @@
/// <reference path='fourslash.ts'/>
////interface A1 { [|a|]: number };
////interface A2 { [|a|]?: number };
////let a1: A1;
////let a2: A2;
////let a12 = { ...a1, ...a2 };
////a12.[|a|];
const ranges = test.ranges();
verify.assertHasRanges(ranges);
// A1 unions with A2, so rename A1.a and a12.a
goTo.position(ranges[0].start);
verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false, [ranges[0], ranges[2]]);
// A1 unions with A2, so rename A2.a and a12.a
goTo.position(ranges[1].start);
verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false, [ranges[1], ranges[2]]);
// a12.a unions A1.a and A2.a, so rename A1.a, A2.a and a12.a
goTo.position(ranges[2].start);
verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false, [ranges[0], ranges[1], ranges[2]]);

View File

@ -0,0 +1,15 @@
/// <reference path='fourslash.ts'/>
////interface Gen {
//// x: number;
//// [|parent|]: Gen;
//// millenial: string;
////}
////let t: Gen;
////var { x, ...rest } = t;
////rest.[|parent|];
const ranges = test.ranges();
verify.assertHasRanges(ranges);
goTo.position(ranges[0].start);
verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false, ranges);
goTo.position(ranges[1].start);
verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false, ranges);