@@ -6232,13 +6232,15 @@ namespace ts {
62326232 const restParameter = sig.parameters[restIndex];
62336233 const restType = getTypeOfSymbol(restParameter);
62346234 if (isTupleType(restType)) {
6235- const elementTypes = (<TypeReference>restType).typeArguments || emptyArray;
6236- const minLength = (<TupleType>(<TypeReference>restType).target).minLength;
6235+ const elementTypes = restType.typeArguments || emptyArray;
6236+ const minLength = restType.target.minLength;
6237+ const tupleRestIndex = restType.target.hasRestElement ? elementTypes.length - 1 : -1;
62376238 const restParams = map(elementTypes, (t, i) => {
62386239 const name = getParameterNameAtPosition(sig, restIndex + i);
6239- const checkFlags = i >= minLength ? CheckFlags.OptionalParameter : 0;
6240+ const checkFlags = i === tupleRestIndex ? CheckFlags.RestParameter :
6241+ i >= minLength ? CheckFlags.OptionalParameter : 0;
62406242 const symbol = createSymbol(SymbolFlags.FunctionScopedVariable, name, checkFlags);
6241- symbol.type = t;
6243+ symbol.type = i === tupleRestIndex ? createArrayType(t) : t;
62426244 return symbol;
62436245 });
62446246 return concatenate(sig.parameters.slice(0, restIndex), restParams);
@@ -8372,7 +8374,7 @@ namespace ts {
83728374 const minLength = findLastIndex(node.elementTypes, n => n.kind !== SyntaxKind.OptionalType && n !== restElement) + 1;
83738375 const elementTypes = map(node.elementTypes, n => {
83748376 const type = getTypeFromTypeNode(n);
8375- return n === restElement ? getIndexTypeOfType(type, IndexKind.Number) || errorType : type;
8377+ return n === restElement && getIndexTypeOfType(type, IndexKind.Number) || type;
83768378 });
83778379 links.resolvedType = createTupleType(elementTypes, minLength, !!restElement);
83788380 }
@@ -8887,6 +8889,12 @@ namespace ts {
88878889 }
88888890 return getTypeOfSymbol(prop);
88898891 }
8892+ if (isTupleType(objectType)) {
8893+ const restType = getRestTypeOfTupleType(objectType);
8894+ if (restType && isNumericLiteralName(propName) && +propName >= 0) {
8895+ return restType;
8896+ }
8897+ }
88908898 }
88918899 if (!(indexType.flags & TypeFlags.Nullable) && isTypeAssignableToKind(indexType, TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbolLike)) {
88928900 if (isTypeAny(objectType)) {
@@ -11343,6 +11351,33 @@ namespace ts {
1134311351 }
1134411352 }
1134511353 let result = Ternary.True;
11354+ if (isTupleType(target)) {
11355+ const targetRestType = getRestTypeOfTupleType(target);
11356+ if (targetRestType) {
11357+ if (!isTupleType(source)) {
11358+ return Ternary.False;
11359+ }
11360+ const sourceRestType = getRestTypeOfTupleType(source);
11361+ if (sourceRestType && !isRelatedTo(sourceRestType, targetRestType, reportErrors)) {
11362+ if (reportErrors) {
11363+ reportError(Diagnostics.Rest_signatures_are_incompatible);
11364+ }
11365+ return Ternary.False;
11366+ }
11367+ const targetCount = getTypeReferenceArity(target) - 1;
11368+ const sourceCount = getTypeReferenceArity(source) - (sourceRestType ? 1 : 0);
11369+ for (let i = targetCount; i < sourceCount; i++) {
11370+ const related = isRelatedTo((<TypeReference>source).typeArguments![i], targetRestType, reportErrors);
11371+ if (!related) {
11372+ if (reportErrors) {
11373+ reportError(Diagnostics.Property_0_is_incompatible_with_rest_element_type, "" + i);
11374+ }
11375+ return Ternary.False;
11376+ }
11377+ result &= related;
11378+ }
11379+ }
11380+ }
1134611381 const properties = getPropertiesOfObjectType(target);
1134711382 for (const targetProp of properties) {
1134811383 if (!(targetProp.flags & SymbolFlags.Prototype)) {
@@ -11417,35 +11452,6 @@ namespace ts {
1141711452 }
1141811453 }
1141911454 }
11420- if (isTupleType(target)) {
11421- const targetRestType = getRestTypeOfTupleType(target);
11422- if (targetRestType) {
11423- if (!isTupleType(source)) {
11424- return Ternary.False;
11425- }
11426- const sourceRestType = getRestTypeOfTupleType(source);
11427- if (sourceRestType && !isRelatedTo(sourceRestType, targetRestType, reportErrors)) {
11428- if (reportErrors) {
11429- // !!! Rest element types are incompatible
11430- reportError(Diagnostics.Index_signatures_are_incompatible);
11431- }
11432- return Ternary.False;
11433- }
11434- const targetCount = getTypeReferenceArity(target) - 1;
11435- const sourceCount = getTypeReferenceArity(source) - (sourceRestType ? 1 : 0);
11436- for (let i = targetCount; i < sourceCount; i++) {
11437- const related = isRelatedTo((<TypeReference>source).typeArguments![i], targetRestType, reportErrors);
11438- if (!related) {
11439- if (reportErrors) {
11440- // !!! Property {0} is incompatible with rest element type
11441- reportError(Diagnostics.Property_0_is_incompatible_with_index_signature, "" + i);
11442- }
11443- return Ternary.False;
11444- }
11445- result &= related;
11446- }
11447- }
11448- }
1144911455 return result;
1145011456 }
1145111457
@@ -12506,7 +12512,7 @@ namespace ts {
1250612512 }
1250712513 const minArgumentCount = getMinArgumentCount(source);
1250812514 const minLength = minArgumentCount < paramCount ? 0 : minArgumentCount - paramCount;
12509- const rest = sourceHasRest ? createArrayType(getUnionType(types)) : createTupleType(types, minLength, /*hasRestElement*/ false , names);
12515+ const rest = createTupleType(types, minLength, sourceHasRest , names);
1251012516 callback(rest, targetRestTypeVariable);
1251112517 }
1251212518 }
@@ -17865,14 +17871,12 @@ namespace ts {
1786517871 }
1786617872 }
1786717873
17874+ function isSpreadArgument(arg: Expression | undefined) {
17875+ return !!arg && (arg.kind === SyntaxKind.SpreadElement || arg.kind === SyntaxKind.SyntheticExpression && (<SyntheticExpression>arg).isSpread);
17876+ }
17877+
1786817878 function getSpreadArgumentIndex(args: ReadonlyArray<Expression>): number {
17869- for (let i = 0; i < args.length; i++) {
17870- const arg = args[i];
17871- if (arg && arg.kind === SyntaxKind.SpreadElement) {
17872- return i;
17873- }
17874- }
17875- return -1;
17879+ return findIndex(args, isSpreadArgument);
1787617880 }
1787717881
1787817882 function hasCorrectArity(node: CallLikeExpression, args: ReadonlyArray<Expression>, signature: Signature, signatureHelpTrailingComma = false) {
@@ -18091,7 +18095,7 @@ namespace ts {
1809118095 function getSpreadArgumentType(node: CallLikeExpression, args: ReadonlyArray<Expression>, index: number, argCount: number, restType: TypeParameter, context: InferenceContext | undefined) {
1809218096 if (index === argCount - 1) {
1809318097 const arg = getEffectiveArgument(node, args, index);
18094- if (arg && arg.kind === SyntaxKind.SpreadElement ) {
18098+ if (isSpreadArgument( arg) ) {
1809518099 // We are inferring from a spread expression in the last argument position, i.e. both the parameter
1809618100 // and the argument are ...x forms.
1809718101 return checkExpressionWithContextualType((<SpreadElement>arg).expression, restType, context);
@@ -18100,16 +18104,20 @@ namespace ts {
1810018104 const contextualType = getIndexTypeOfType(restType, IndexKind.Number) || anyType;
1810118105 const hasPrimitiveContextualType = maybeTypeOfKind(contextualType, TypeFlags.Primitive | TypeFlags.Index);
1810218106 const types = [];
18103- let hasSpreadExpression = false ;
18107+ let spreadIndex = -1 ;
1810418108 for (let i = index; i < argCount; i++) {
1810518109 let argType = getEffectiveArgumentType(node, i);
1810618110 if (!argType) {
1810718111 argType = checkExpressionWithContextualType(args[i], contextualType, context);
18108- hasSpreadExpression = hasSpreadExpression || args[i].kind === SyntaxKind.SpreadElement;
18112+ if (spreadIndex < 0 && isSpreadArgument(args[i])) {
18113+ spreadIndex = i - index;
18114+ }
1810918115 }
1811018116 types.push(hasPrimitiveContextualType ? getRegularTypeOfLiteralType(argType) : getWidenedLiteralType(argType));
1811118117 }
18112- return hasSpreadExpression ? createArrayType(getUnionType(types)) : createTupleType(types);
18118+ return spreadIndex < 0 ?
18119+ createTupleType(types) :
18120+ createTupleType(append(types.slice(0, spreadIndex), getUnionType(types.slice(spreadIndex))), spreadIndex, /*hasRestElement*/ true);
1811318121 }
1811418122
1811518123 function checkTypeArguments(signature: Signature, typeArgumentNodes: ReadonlyArray<TypeNode>, reportErrors: boolean, headMessage?: DiagnosticMessage): Type[] | false {
@@ -18205,7 +18213,7 @@ namespace ts {
1820518213 const arg = getEffectiveArgument(node, args, i);
1820618214 // If the effective argument is 'undefined', then it is an argument that is present but is synthetic.
1820718215 if (arg === undefined || arg.kind !== SyntaxKind.OmittedExpression) {
18208- if (i === restIndex && (restType.flags & TypeFlags.TypeParameter || arg && arg.kind === SyntaxKind.SpreadElement && !isArrayType(restType))) {
18216+ if (i === restIndex && (restType.flags & TypeFlags.TypeParameter || isSpreadArgument( arg) && !isArrayType(restType))) {
1820918217 const spreadType = getSpreadArgumentType(node, args, i, argCount, restType, /*context*/ undefined);
1821018218 return checkTypeRelatedTo(spreadType, restType, relation, arg, headMessage);
1821118219 }
@@ -18275,17 +18283,20 @@ namespace ts {
1827518283 else {
1827618284 const args = node.arguments || emptyArray;
1827718285 const length = args.length;
18278- if (length && args[length - 1].kind === SyntaxKind.SpreadElement && getSpreadArgumentIndex(args) === length - 1) {
18286+ if (length && isSpreadArgument( args[length - 1]) && getSpreadArgumentIndex(args) === length - 1) {
1827918287 // We have a spread argument in the last position and no other spread arguments. If the type
1828018288 // of the argument is a tuple type, spread the tuple elements into the argument list. We can
1828118289 // call checkExpressionCached because spread expressions never have a contextual type.
1828218290 const spreadArgument = <SpreadElement>args[length - 1];
1828318291 const type = checkExpressionCached(spreadArgument.expression);
1828418292 if (isTupleType(type)) {
18285- const syntheticArgs = map((<TypeReference>type).typeArguments || emptyArray, t => {
18293+ const typeArguments = (<TypeReference>type).typeArguments || emptyArray;
18294+ const restIndex = type.target.hasRestElement ? typeArguments.length - 1 : -1;
18295+ const syntheticArgs = map(typeArguments, (t, i) => {
1828618296 const arg = <SyntheticExpression>createNode(SyntaxKind.SyntheticExpression, spreadArgument.pos, spreadArgument.end);
1828718297 arg.parent = spreadArgument;
1828818298 arg.type = t;
18299+ arg.isSpread = i === restIndex;
1828918300 return arg;
1829018301 });
1829118302 return concatenate(args.slice(0, length - 1), syntheticArgs);
@@ -19601,9 +19612,12 @@ namespace ts {
1960119612 if (signature.hasRestParameter) {
1960219613 const restType = getTypeOfSymbol(signature.parameters[paramCount]);
1960319614 if (isTupleType(restType)) {
19604- const elementCount = ((<TypeReference>restType).typeArguments || emptyArray).length;
19605- if (pos - paramCount < elementCount) {
19606- return (<TypeReference>restType).typeArguments![pos - paramCount];
19615+ if (pos - paramCount < getLengthOfTupleType(restType)) {
19616+ return restType.typeArguments![pos - paramCount];
19617+ }
19618+ const tupleRestType = getRestTypeOfTupleType(restType);
19619+ if (tupleRestType) {
19620+ return tupleRestType;
1960719621 }
1960819622 }
1960919623 return getIndexTypeOfType(restType, IndexKind.Number) || anyType;
@@ -19612,26 +19626,35 @@ namespace ts {
1961219626 }
1961319627
1961419628 function getTypeOfRestParameter(signature: Signature) {
19615- return signature.hasRestParameter ? getTypeOfSymbol(signature.parameters[signature.parameters.length - 1]) : undefined;
19629+ if (signature.hasRestParameter) {
19630+ const restType = getTypeOfSymbol(signature.parameters[signature.parameters.length - 1]);
19631+ if (isTupleType(restType)) {
19632+ return getRestTypeOfTupleType(restType);
19633+ }
19634+ return restType;
19635+ }
19636+ return undefined;
1961619637 }
1961719638
1961819639 function getParameterCount(signature: Signature) {
1961919640 const length = signature.parameters.length;
1962019641 if (signature.hasRestParameter) {
1962119642 const restType = getTypeOfSymbol(signature.parameters[length - 1]);
1962219643 if (isTupleType(restType)) {
19623- return length + ((<TypeReference> restType) .typeArguments || emptyArray).length - 1;
19644+ return length + (restType.typeArguments || emptyArray).length - 1;
1962419645 }
1962519646 }
1962619647 return length;
1962719648 }
1962819649
1962919650 function getMinArgumentCount(signature: Signature) {
19630- const restType = getTypeOfRestParameter(signature);
19631- if (restType && isTupleType(restType)) {
19632- const minLength = (<TupleType>(<TypeReference>restType).target).minLength;
19633- if (minLength > 0) {
19634- return signature.parameters.length - 1 + minLength;
19651+ if (signature.hasRestParameter) {
19652+ const restType = getTypeOfSymbol(signature.parameters[signature.parameters.length - 1]);
19653+ if (isTupleType(restType)) {
19654+ const minLength = restType.target.minLength;
19655+ if (minLength > 0) {
19656+ return signature.parameters.length - 1 + minLength;
19657+ }
1963519658 }
1963619659 }
1963719660 return signature.minArgumentCount;
@@ -19648,7 +19671,11 @@ namespace ts {
1964819671 }
1964919672
1965019673 function hasEffectiveRestParameter(signature: Signature) {
19651- return signature.hasRestParameter && !isTupleType(getTypeOfSymbol(signature.parameters[signature.parameters.length - 1]));
19674+ if (signature.hasRestParameter) {
19675+ const restType = getTypeOfSymbol(signature.parameters[signature.parameters.length - 1]);
19676+ return !isTupleType(restType) || restType.target.hasRestElement;
19677+ }
19678+ return false;
1965219679 }
1965319680
1965419681 function getTypeOfFirstParameterOfSignature(signature: Signature) {
@@ -21928,6 +21955,27 @@ namespace ts {
2192821955 }
2192921956
2193021957 function checkTupleType(node: TupleTypeNode) {
21958+ const elementTypes = node.elementTypes;
21959+ let seenOptionalElement = false;
21960+ for (let i = 0; i < elementTypes.length; i++) {
21961+ const e = elementTypes[i];
21962+ if (e.kind === SyntaxKind.RestType) {
21963+ if (i !== elementTypes.length - 1) {
21964+ grammarErrorOnNode(e, Diagnostics.A_rest_element_must_be_last_in_a_tuple_type);
21965+ break;
21966+ }
21967+ if (!isArrayType(getTypeFromTypeNode(e))) {
21968+ error(e, Diagnostics.A_rest_element_type_must_be_an_array_type);
21969+ }
21970+ }
21971+ else if (e.kind === SyntaxKind.OptionalType) {
21972+ seenOptionalElement = true;
21973+ }
21974+ else if (seenOptionalElement) {
21975+ grammarErrorOnNode(e, Diagnostics.A_required_element_cannot_follow_an_optional_element);
21976+ break;
21977+ }
21978+ }
2193121979 checkGrammarForDisallowedTrailingComma(node.elementTypes);
2193221980 forEach(node.elementTypes, checkSourceElement);
2193321981 }
0 commit comments