@@ -6232,13 +6232,15 @@ namespace ts {
6232
6232
const restParameter = sig.parameters[restIndex];
6233
6233
const restType = getTypeOfSymbol(restParameter);
6234
6234
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;
6237
6238
const restParams = map(elementTypes, (t, i) => {
6238
6239
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;
6240
6242
const symbol = createSymbol(SymbolFlags.FunctionScopedVariable, name, checkFlags);
6241
- symbol.type = t;
6243
+ symbol.type = i === tupleRestIndex ? createArrayType(t) : t;
6242
6244
return symbol;
6243
6245
});
6244
6246
return concatenate(sig.parameters.slice(0, restIndex), restParams);
@@ -8372,7 +8374,7 @@ namespace ts {
8372
8374
const minLength = findLastIndex(node.elementTypes, n => n.kind !== SyntaxKind.OptionalType && n !== restElement) + 1;
8373
8375
const elementTypes = map(node.elementTypes, n => {
8374
8376
const type = getTypeFromTypeNode(n);
8375
- return n === restElement ? getIndexTypeOfType(type, IndexKind.Number) || errorType : type;
8377
+ return n === restElement && getIndexTypeOfType(type, IndexKind.Number) || type;
8376
8378
});
8377
8379
links.resolvedType = createTupleType(elementTypes, minLength, !!restElement);
8378
8380
}
@@ -8887,6 +8889,12 @@ namespace ts {
8887
8889
}
8888
8890
return getTypeOfSymbol(prop);
8889
8891
}
8892
+ if (isTupleType(objectType)) {
8893
+ const restType = getRestTypeOfTupleType(objectType);
8894
+ if (restType && isNumericLiteralName(propName) && +propName >= 0) {
8895
+ return restType;
8896
+ }
8897
+ }
8890
8898
}
8891
8899
if (!(indexType.flags & TypeFlags.Nullable) && isTypeAssignableToKind(indexType, TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbolLike)) {
8892
8900
if (isTypeAny(objectType)) {
@@ -11343,6 +11351,33 @@ namespace ts {
11343
11351
}
11344
11352
}
11345
11353
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
+ }
11346
11381
const properties = getPropertiesOfObjectType(target);
11347
11382
for (const targetProp of properties) {
11348
11383
if (!(targetProp.flags & SymbolFlags.Prototype)) {
@@ -11417,35 +11452,6 @@ namespace ts {
11417
11452
}
11418
11453
}
11419
11454
}
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
- }
11449
11455
return result;
11450
11456
}
11451
11457
@@ -12506,7 +12512,7 @@ namespace ts {
12506
12512
}
12507
12513
const minArgumentCount = getMinArgumentCount(source);
12508
12514
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);
12510
12516
callback(rest, targetRestTypeVariable);
12511
12517
}
12512
12518
}
@@ -17865,14 +17871,12 @@ namespace ts {
17865
17871
}
17866
17872
}
17867
17873
17874
+ function isSpreadArgument(arg: Expression | undefined) {
17875
+ return !!arg && (arg.kind === SyntaxKind.SpreadElement || arg.kind === SyntaxKind.SyntheticExpression && (<SyntheticExpression>arg).isSpread);
17876
+ }
17877
+
17868
17878
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);
17876
17880
}
17877
17881
17878
17882
function hasCorrectArity(node: CallLikeExpression, args: ReadonlyArray<Expression>, signature: Signature, signatureHelpTrailingComma = false) {
@@ -18091,7 +18095,7 @@ namespace ts {
18091
18095
function getSpreadArgumentType(node: CallLikeExpression, args: ReadonlyArray<Expression>, index: number, argCount: number, restType: TypeParameter, context: InferenceContext | undefined) {
18092
18096
if (index === argCount - 1) {
18093
18097
const arg = getEffectiveArgument(node, args, index);
18094
- if (arg && arg.kind === SyntaxKind.SpreadElement ) {
18098
+ if (isSpreadArgument( arg) ) {
18095
18099
// We are inferring from a spread expression in the last argument position, i.e. both the parameter
18096
18100
// and the argument are ...x forms.
18097
18101
return checkExpressionWithContextualType((<SpreadElement>arg).expression, restType, context);
@@ -18100,16 +18104,20 @@ namespace ts {
18100
18104
const contextualType = getIndexTypeOfType(restType, IndexKind.Number) || anyType;
18101
18105
const hasPrimitiveContextualType = maybeTypeOfKind(contextualType, TypeFlags.Primitive | TypeFlags.Index);
18102
18106
const types = [];
18103
- let hasSpreadExpression = false ;
18107
+ let spreadIndex = -1 ;
18104
18108
for (let i = index; i < argCount; i++) {
18105
18109
let argType = getEffectiveArgumentType(node, i);
18106
18110
if (!argType) {
18107
18111
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
+ }
18109
18115
}
18110
18116
types.push(hasPrimitiveContextualType ? getRegularTypeOfLiteralType(argType) : getWidenedLiteralType(argType));
18111
18117
}
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);
18113
18121
}
18114
18122
18115
18123
function checkTypeArguments(signature: Signature, typeArgumentNodes: ReadonlyArray<TypeNode>, reportErrors: boolean, headMessage?: DiagnosticMessage): Type[] | false {
@@ -18205,7 +18213,7 @@ namespace ts {
18205
18213
const arg = getEffectiveArgument(node, args, i);
18206
18214
// If the effective argument is 'undefined', then it is an argument that is present but is synthetic.
18207
18215
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))) {
18209
18217
const spreadType = getSpreadArgumentType(node, args, i, argCount, restType, /*context*/ undefined);
18210
18218
return checkTypeRelatedTo(spreadType, restType, relation, arg, headMessage);
18211
18219
}
@@ -18275,17 +18283,20 @@ namespace ts {
18275
18283
else {
18276
18284
const args = node.arguments || emptyArray;
18277
18285
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) {
18279
18287
// We have a spread argument in the last position and no other spread arguments. If the type
18280
18288
// of the argument is a tuple type, spread the tuple elements into the argument list. We can
18281
18289
// call checkExpressionCached because spread expressions never have a contextual type.
18282
18290
const spreadArgument = <SpreadElement>args[length - 1];
18283
18291
const type = checkExpressionCached(spreadArgument.expression);
18284
18292
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) => {
18286
18296
const arg = <SyntheticExpression>createNode(SyntaxKind.SyntheticExpression, spreadArgument.pos, spreadArgument.end);
18287
18297
arg.parent = spreadArgument;
18288
18298
arg.type = t;
18299
+ arg.isSpread = i === restIndex;
18289
18300
return arg;
18290
18301
});
18291
18302
return concatenate(args.slice(0, length - 1), syntheticArgs);
@@ -19601,9 +19612,12 @@ namespace ts {
19601
19612
if (signature.hasRestParameter) {
19602
19613
const restType = getTypeOfSymbol(signature.parameters[paramCount]);
19603
19614
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;
19607
19621
}
19608
19622
}
19609
19623
return getIndexTypeOfType(restType, IndexKind.Number) || anyType;
@@ -19612,26 +19626,35 @@ namespace ts {
19612
19626
}
19613
19627
19614
19628
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;
19616
19637
}
19617
19638
19618
19639
function getParameterCount(signature: Signature) {
19619
19640
const length = signature.parameters.length;
19620
19641
if (signature.hasRestParameter) {
19621
19642
const restType = getTypeOfSymbol(signature.parameters[length - 1]);
19622
19643
if (isTupleType(restType)) {
19623
- return length + ((<TypeReference> restType) .typeArguments || emptyArray).length - 1;
19644
+ return length + (restType.typeArguments || emptyArray).length - 1;
19624
19645
}
19625
19646
}
19626
19647
return length;
19627
19648
}
19628
19649
19629
19650
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
+ }
19635
19658
}
19636
19659
}
19637
19660
return signature.minArgumentCount;
@@ -19648,7 +19671,11 @@ namespace ts {
19648
19671
}
19649
19672
19650
19673
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;
19652
19679
}
19653
19680
19654
19681
function getTypeOfFirstParameterOfSignature(signature: Signature) {
@@ -21928,6 +21955,27 @@ namespace ts {
21928
21955
}
21929
21956
21930
21957
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
+ }
21931
21979
checkGrammarForDisallowedTrailingComma(node.elementTypes);
21932
21980
forEach(node.elementTypes, checkSourceElement);
21933
21981
}
0 commit comments