@@ -3952,6 +3952,9 @@ namespace ts {
3952
3952
if (type.flags & TypeFlags.Reference && (<TypeReference>type).target === globalArrayType) {
3953
3953
return (<TypeReference>type).typeArguments[0];
3954
3954
}
3955
+ else if (type.flags & TypeFlags.TupleKind) {
3956
+ return type;
3957
+ }
3955
3958
}
3956
3959
return anyType;
3957
3960
}
@@ -5823,8 +5826,8 @@ namespace ts {
5823
5826
return !!getPropertyOfType(type, "0");
5824
5827
}
5825
5828
5826
- function isStringLiteralType(type: Type) {
5827
- return type.flags & TypeFlags.StringLiteral;
5829
+ function isStringLiteralType(type: Type): boolean {
5830
+ return !!( type.flags & TypeFlags.StringLiteral) ;
5828
5831
}
5829
5832
5830
5833
/**
@@ -6059,30 +6062,55 @@ namespace ts {
6059
6062
return;
6060
6063
}
6061
6064
6062
- const typeParameters = context.typeParameters;
6063
- for (let i = 0; i < typeParameters.length; i++) {
6064
- if (target === typeParameters[i]) {
6065
- const inferences = context.inferences[i];
6066
- if (!inferences.isFixed) {
6067
- // Any inferences that are made to a type parameter in a union type are inferior
6068
- // to inferences made to a flat (non-union) type. This is because if we infer to
6069
- // T | string[], we really don't know if we should be inferring to T or not (because
6070
- // the correct constituent on the target side could be string[]). Therefore, we put
6071
- // such inferior inferences into a secondary bucket, and only use them if the primary
6072
- // bucket is empty.
6073
- const candidates = inferiority ?
6074
- inferences.secondary || (inferences.secondary = []) :
6075
- inferences.primary || (inferences.primary = []);
6076
- if (!contains(candidates, source)) {
6077
- candidates.push(source);
6078
- }
6065
+ const i = indexOf(context.typeParameters, target);
6066
+ if (i > -1) {
6067
+ const inferences = context.inferences[i];
6068
+ if (!inferences.isFixed) {
6069
+ // Any inferences that are made to a type parameter in a union type are inferior
6070
+ // to inferences made to a flat (non-union) type. This is because if we infer to
6071
+ // T | string[], we really don't know if we should be inferring to T or not (because
6072
+ // the correct constituent on the target side could be string[]). Therefore, we put
6073
+ // such inferior inferences into a secondary bucket, and only use them if the primary
6074
+ // bucket is empty.
6075
+ const candidates = inferiority ?
6076
+ inferences.secondary || (inferences.secondary = []) :
6077
+ inferences.primary || (inferences.primary = []);
6078
+ if (!contains(candidates, source)) {
6079
+ candidates.push(source);
6079
6080
}
6080
- return;
6081
6081
}
6082
+ return;
6082
6083
}
6083
6084
}
6084
6085
else if (target.flags & TypeFlags.TupleKind) {
6085
- // TODO: Some stuff here. It should look a LOT like the previous branch, so maybe just merge the two.
6086
+ // TODO: Source should be a tuple for us to infer anything.
6087
+ // If it's a tuple, I think the code will be nearly the same as the previous branch.
6088
+
6089
+ // If target is a type parameter, make an inference if the source type is a tuple-like type.
6090
+ // If it's not, hopefully it will get fixed to a tuple and the second (nth?) round of inference will succeed.
6091
+ if (!isTupleLikeType(source)) {
6092
+ return;
6093
+ }
6094
+
6095
+ const i = indexOf(context.typeParameters, target);
6096
+ if (i > -1) {
6097
+ const inferences = context.inferences[i];
6098
+ if (!inferences.isFixed) {
6099
+ // Any inferences that are made to a type parameter in a union type are inferior
6100
+ // to inferences made to a flat (non-union) type. This is because if we infer to
6101
+ // T | string[], we really don't know if we should be inferring to T or not (because
6102
+ // the correct constituent on the target side could be string[]). Therefore, we put
6103
+ // such inferior inferences into a secondary bucket, and only use them if the primary
6104
+ // bucket is empty.
6105
+ const candidates = inferiority ?
6106
+ inferences.secondary || (inferences.secondary = []) :
6107
+ inferences.primary || (inferences.primary = []);
6108
+ if (!contains(candidates, source)) {
6109
+ candidates.push(source);
6110
+ }
6111
+ }
6112
+ return;
6113
+ }
6086
6114
}
6087
6115
else if (source.flags & TypeFlags.Reference && target.flags & TypeFlags.Reference && (<TypeReference>source).target === (<TypeReference>target).target) {
6088
6116
// If source and target are references to the same generic type, infer from type arguments
@@ -6111,10 +6139,10 @@ namespace ts {
6111
6139
typeParameter = <TypeParameter>t;
6112
6140
typeParameterCount++;
6113
6141
}
6114
- else if(t.flags & TypeFlags.TupleKind) {
6142
+ else if (t.flags & TypeFlags.TupleKind) {
6115
6143
// TODO: freak out and throw up our hands!! (I don't think spreading kinds across unions should be in v1 -- this should be checked elsewhere)
6116
6144
// For now, throw a useless string.
6117
- throw ' oh no!' ;
6145
+ throw " oh no!" ;
6118
6146
}
6119
6147
else {
6120
6148
inferFromTypes(source, t);
@@ -7120,13 +7148,20 @@ namespace ts {
7120
7148
return applyToContextualType(type, t => getIndexTypeOfStructuredType(t, kind));
7121
7149
}
7122
7150
7151
+ function contextualTypeIs (typePredicate: (t: Type) => boolean, t: Type): boolean {
7152
+ return !!(t.flags & TypeFlags.Union ? forEach((<UnionType>t).types, typePredicate) : typePredicate(t));
7153
+ }
7154
+
7123
7155
function contextualTypeIsStringLiteralType(type: Type): boolean {
7124
- return !!(type.flags & TypeFlags.Union ? forEach((<UnionType>type).types, isStringLiteralType) : isStringLiteralType( type) );
7156
+ return contextualTypeIs(isStringLiteralType, type);
7125
7157
}
7126
7158
7127
- // Return true if the given contextual type is a tuple-like type
7128
7159
function contextualTypeIsTupleLikeType(type: Type): boolean {
7129
- return !!(type.flags & TypeFlags.Union ? forEach((<UnionType>type).types, isTupleLikeType) : isTupleLikeType(type));
7160
+ return contextualTypeIs(isTupleLikeType, type);
7161
+ }
7162
+
7163
+ function contextualTypeIsTupleKind(type: Type): boolean {
7164
+ return contextualTypeIs(isTupleKind, type);
7130
7165
}
7131
7166
7132
7167
// Return true if the given contextual type provides an index signature of the given kind
@@ -7461,6 +7496,12 @@ namespace ts {
7461
7496
return createTupleType(elementTypes);
7462
7497
}
7463
7498
}
7499
+ else if (contextualType && contextualTypeIsTupleKind(contextualType)) {
7500
+ // TODO: Handle contextual typing by a binding pattern
7501
+ if (elementTypes.length) {
7502
+ return createTupleType(elementTypes);
7503
+ }
7504
+ }
7464
7505
}
7465
7506
return createArrayType(elementTypes.length ? getUnionType(elementTypes) : undefinedType);
7466
7507
}
@@ -8615,11 +8656,11 @@ namespace ts {
8615
8656
8616
8657
// On this call to inferTypeArguments, we may get more inferences for certain type parameters that were not
8617
8658
// fixed last time. This means that a type parameter that failed inference last time may succeed this time,
8618
- // or vice versa. Therefore, the failedTypeParameterIndex is useless if it points to an unfixed type parameter,
8619
- // because it may change. So here we reset it. However, getInferredType will not revisit any type parameters
8620
- // that were previously fixed. So if a fixed type parameter failed previously, it will fail again because
8621
- // it will contain the exact same set of inferences. So if we reset the index from a fixed type parameter,
8622
- // we will lose information that we won't recover this time around.
8659
+ // or vice versa. Therefore, ` failedTypeParameterIndex` is useless if it points to an unfixed type parameter,
8660
+ // because it may change. So here we reset it if it's already fixed: getInferredType will not revisit any type parameters
8661
+ // that were previously fixed. If a fixed type parameter failed previously, it will fail again because
8662
+ // it will contain the exact same set of inferences. What's worse, resetting a fixed type parameter means that
8663
+ // we would lose information that we won't recover this time around.
8623
8664
if (context.failedTypeParameterIndex !== undefined && !context.inferences[context.failedTypeParameterIndex].isFixed) {
8624
8665
context.failedTypeParameterIndex = undefined;
8625
8666
}
@@ -9172,7 +9213,7 @@ namespace ts {
9172
9213
}
9173
9214
9174
9215
// No signature was applicable. We have already reported the errors for the invalid signature.
9175
- // If this is a type resolution session, e.g. Language Service, try to get better information that anySignature.
9216
+ // If this is a type resolution session, e.g. Language Service, try to get better information than anySignature.
9176
9217
// Pick the first candidate that matches the arity. This way we can get a contextual type for cases like:
9177
9218
// declare function f(a: { xa: number; xb: number; });
9178
9219
// f({ |
0 commit comments