mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-15 11:35:42 -06:00
Properly handle unions of tuple types
This commit is contained in:
parent
c9ea6c3e03
commit
7f3f98ea83
@ -4681,14 +4681,14 @@ namespace ts {
|
||||
// If the parent is a tuple type, the rest element has a tuple type of the
|
||||
// remaining tuple element types. Otherwise, the rest element has an array type with same
|
||||
// element type as the parent type.
|
||||
type = isTupleType(parentType) ?
|
||||
sliceTupleType(parentType, index) :
|
||||
type = everyType(parentType, isTupleType) ?
|
||||
mapType(parentType, t => sliceTupleType(<TupleTypeReference>t, index)) :
|
||||
createArrayType(elementType);
|
||||
}
|
||||
else {
|
||||
// Use specific property type when parent is a tuple or numeric index type when parent is an array
|
||||
const index = pattern.elements.indexOf(declaration);
|
||||
type = isTupleLikeType(parentType) ?
|
||||
type = everyType(parentType, isTupleLikeType) ?
|
||||
getTupleElementType(parentType, index) || declaration.initializer && checkDeclarationInitializer(declaration) :
|
||||
elementType;
|
||||
if (!type) {
|
||||
@ -7307,10 +7307,10 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
else if (isUnion) {
|
||||
const index = !isLateBoundName(name) && ((isNumericLiteralName(name) && getIndexInfoOfType(type, IndexKind.Number)) || getIndexInfoOfType(type, IndexKind.String));
|
||||
if (index) {
|
||||
checkFlags |= index.isReadonly ? CheckFlags.Readonly : 0;
|
||||
indexTypes = append(indexTypes, index.type);
|
||||
const indexInfo = !isLateBoundName(name) && (isNumericLiteralName(name) && getIndexInfoOfType(type, IndexKind.Number) || getIndexInfoOfType(type, IndexKind.String));
|
||||
if (indexInfo) {
|
||||
checkFlags |= indexInfo.isReadonly ? CheckFlags.Readonly : 0;
|
||||
indexTypes = append(indexTypes, isTupleType(type) ? getRestTypeOfTupleType(type) || undefinedType : indexInfo.type);
|
||||
}
|
||||
else {
|
||||
checkFlags |= CheckFlags.Partial;
|
||||
@ -9307,11 +9307,8 @@ namespace ts {
|
||||
const propType = getTypeOfSymbol(prop);
|
||||
return accessExpression ? getFlowTypeOfReference(accessExpression, propType) : propType;
|
||||
}
|
||||
if (isTupleType(objectType)) {
|
||||
const restType = getRestTypeOfTupleType(objectType);
|
||||
if (restType && isNumericLiteralName(propName) && +propName >= 0) {
|
||||
return restType;
|
||||
}
|
||||
if (everyType(objectType, isTupleType) && isNumericLiteralName(propName) && +propName >= 0) {
|
||||
return mapType(objectType, t => getRestTypeOfTupleType(<TupleTypeReference>t) || undefinedType);
|
||||
}
|
||||
}
|
||||
if (!(indexType.flags & TypeFlags.Nullable) && isTypeAssignableToKind(indexType, TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbolLike)) {
|
||||
@ -12867,9 +12864,17 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getTupleElementType(type: Type, index: number) {
|
||||
return isTupleType(type) ?
|
||||
index < getLengthOfTupleType(type) ? type.typeArguments![index] : getRestTypeOfTupleType(type) :
|
||||
getTypeOfPropertyOfType(type, "" + index as __String);
|
||||
const propType = getTypeOfPropertyOfType(type, "" + index as __String);
|
||||
if (propType) {
|
||||
return propType;
|
||||
}
|
||||
if (everyType(type, isTupleType)) {
|
||||
let restType = mapType(type, t => getRestTypeOfTupleType(<TupleTypeReference>t) || undefinedType);
|
||||
if (restType !== undefinedType) {
|
||||
return restType;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function isNeitherUnitTypeNorNever(type: Type): boolean {
|
||||
@ -14361,7 +14366,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getTypeOfDestructuredArrayElement(type: Type, index: number) {
|
||||
return isTupleLikeType(type) && getTupleElementType(type, index) ||
|
||||
return everyType(type, isTupleLikeType) && getTupleElementType(type, index) ||
|
||||
checkIteratedTypeOrElementType(type, /*errorNode*/ undefined, /*allowStringInput*/ false, /*allowAsyncIterables*/ false) ||
|
||||
errorType;
|
||||
}
|
||||
@ -14559,6 +14564,10 @@ namespace ts {
|
||||
return type.flags & TypeFlags.Union ? forEach((<UnionType>type).types, f) : f(type);
|
||||
}
|
||||
|
||||
function everyType(type: Type, f: (t: Type) => boolean): boolean {
|
||||
return type.flags & TypeFlags.Union ? every((<UnionType>type).types, f) : f(type);
|
||||
}
|
||||
|
||||
function filterType(type: Type, f: (t: Type) => boolean): Type {
|
||||
if (type.flags & TypeFlags.Union) {
|
||||
const types = (<UnionType>type).types;
|
||||
@ -16657,11 +16666,6 @@ namespace ts {
|
||||
return mapType(type, t => getIndexTypeOfStructuredType(t, kind), /*noReductions*/ true);
|
||||
}
|
||||
|
||||
// Return true if the given contextual type is a tuple-like type
|
||||
function contextualTypeIsTupleLikeType(type: Type): boolean {
|
||||
return !!(type.flags & TypeFlags.Union ? forEach((<UnionType>type).types, isTupleLikeType) : isTupleLikeType(type));
|
||||
}
|
||||
|
||||
// In an object literal contextually typed by a type T, the contextual type of a property assignment is the type of
|
||||
// the matching property in T, if one exists. Otherwise, it is the type of the numeric index signature in T, if one
|
||||
// exists. Otherwise, it is the type of the string index signature in T, if one exists.
|
||||
@ -17191,7 +17195,8 @@ namespace ts {
|
||||
type.pattern = node;
|
||||
return type;
|
||||
}
|
||||
if (contextualType && contextualTypeIsTupleLikeType(contextualType)) {
|
||||
// Infer a tuple type when the contextual type is or contains a tuple-like type
|
||||
if (contextualType && forEachType(contextualType, isTupleLikeType)) {
|
||||
const pattern = contextualType.pattern;
|
||||
// If array literal is contextually typed by a binding pattern or an assignment pattern, pad the resulting
|
||||
// tuple type with the corresponding binding or assignment element types to make the lengths equal.
|
||||
@ -18925,9 +18930,9 @@ namespace ts {
|
||||
}
|
||||
if (isTupleType(objectType) && !objectType.target.hasRestElement && isNumericLiteral(indexExpression)) {
|
||||
const index = +indexExpression.text;
|
||||
const maximumIndex = length(objectType.target.typeParameters);
|
||||
if (index >= maximumIndex) {
|
||||
error(indexExpression, Diagnostics.Index_0_is_out_of_bounds_in_tuple_of_length_1, index, maximumIndex);
|
||||
const length = getTypeReferenceArity(objectType);
|
||||
if (index >= length) {
|
||||
error(indexExpression, Diagnostics.Index_0_is_out_of_bounds_in_tuple_of_length_1, index, length);
|
||||
}
|
||||
}
|
||||
|
||||
@ -21668,7 +21673,7 @@ namespace ts {
|
||||
if (element.kind !== SyntaxKind.SpreadElement) {
|
||||
const propName = "" + elementIndex as __String;
|
||||
const type = isTypeAny(sourceType) ? sourceType :
|
||||
isTupleLikeType(sourceType) ? getTupleElementType(sourceType, elementIndex) :
|
||||
everyType(sourceType, isTupleLikeType) ? getTupleElementType(sourceType, elementIndex) :
|
||||
elementType;
|
||||
if (type) {
|
||||
return checkDestructuringAssignment(element, type, checkMode);
|
||||
@ -21694,8 +21699,8 @@ namespace ts {
|
||||
}
|
||||
else {
|
||||
checkGrammarForDisallowedTrailingComma(node.elements, Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma);
|
||||
const type = isTupleType(sourceType) ?
|
||||
sliceTupleType(sourceType, elementIndex) :
|
||||
const type = everyType(sourceType, isTupleType) ?
|
||||
mapType(sourceType, t => sliceTupleType(<TupleTypeReference>t, elementIndex)) :
|
||||
createArrayType(elementType);
|
||||
return checkDestructuringAssignment(restExpression, type, checkMode);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user