Simplify indexTypesRelatedTo function

This commit is contained in:
Anders Hejlsberg
2016-02-11 06:18:04 -08:00
parent bb7ba1dcea
commit 5f95c75403
+39 -73
View File
@@ -5760,9 +5760,9 @@ namespace ts {
if (result) {
result &= signaturesRelatedTo(source, target, SignatureKind.Construct, reportErrors);
if (result) {
result &= stringIndexTypesRelatedTo(source, originalSource, target, reportErrors);
result &= indexTypesRelatedTo(source, originalSource, target, IndexKind.String, reportErrors);
if (result) {
result &= numberIndexTypesRelatedTo(source, originalSource, target, reportErrors);
result &= indexTypesRelatedTo(source, originalSource, target, IndexKind.Number, reportErrors);
}
}
}
@@ -5964,10 +5964,10 @@ namespace ts {
return result;
}
function eachPropertyRelatedTo(source: Type, target: Type, numericPropertiesOnly: boolean, reportErrors: boolean): Ternary {
function eachPropertyRelatedTo(source: Type, target: Type, kind: IndexKind, reportErrors: boolean): Ternary {
let result = Ternary.True;
for (const prop of getPropertiesOfObjectType(source)) {
if (!numericPropertiesOnly || isNumericLiteralName(prop.name)) {
if (kind === IndexKind.String || isNumericLiteralName(prop.name)) {
const related = isRelatedTo(getTypeOfSymbol(prop), target, reportErrors);
if (!related) {
if (reportErrors) {
@@ -5981,82 +5981,48 @@ namespace ts {
return result;
}
function stringIndexTypesRelatedTo(source: Type, originalSource: Type, target: Type, reportErrors: boolean): Ternary {
if (relation === identityRelation) {
return indexTypesIdenticalTo(IndexKind.String, source, target);
function indexInfoRelatedTo(sourceInfo: IndexInfo, targetInfo: IndexInfo, reportErrors: boolean) {
const related = isRelatedTo(sourceInfo.type, targetInfo.type, reportErrors);
if (!related && reportErrors) {
reportError(Diagnostics.Index_signatures_are_incompatible);
}
const targetInfo = getIndexInfoOfType(target, IndexKind.String);
if (targetInfo) {
if ((targetInfo.type.flags & TypeFlags.Any) && !(originalSource.flags & TypeFlags.Primitive)) {
// non-primitive assignment to any is always allowed, eg
// `var x: { [index: string]: any } = { property: 12 };`
return Ternary.True;
return related;
}
function indexTypesRelatedTo(source: Type, originalSource: Type, target: Type, kind: IndexKind, reportErrors: boolean) {
if (relation === identityRelation) {
return indexTypesIdenticalTo(source, target, kind);
}
const targetInfo = getIndexInfoOfType(target, kind);
if (!targetInfo || ((targetInfo.type.flags & TypeFlags.Any) && !(originalSource.flags & TypeFlags.Primitive))) {
// Index signature of type any permits assignment from everything but primitives
return Ternary.True;
}
const sourceInfo = getIndexInfoOfType(source, kind) ||
kind === IndexKind.Number && getIndexInfoOfType(source, IndexKind.String);
if (sourceInfo) {
return indexInfoRelatedTo(sourceInfo, targetInfo, reportErrors);
}
if (isObjectLiteralType(source)) {
let related = Ternary.True;
if (kind === IndexKind.String) {
const sourceNumberInfo = getIndexInfoOfType(source, IndexKind.Number);
if (sourceNumberInfo) {
related = indexInfoRelatedTo(sourceNumberInfo, targetInfo, reportErrors);
}
}
const sourceInfo = getIndexInfoOfType(source, IndexKind.String);
if (!sourceInfo) {
if (isObjectLiteralType(source)) {
return eachPropertyRelatedTo(source, targetInfo.type, /* numericPropertiesOnly*/ false, reportErrors);
}
if (reportErrors) {
reportError(Diagnostics.Index_signature_is_missing_in_type_0, typeToString(source));
}
return Ternary.False;
}
const related = isRelatedTo(sourceInfo.type, targetInfo.type, reportErrors);
if (!related) {
if (reportErrors) {
reportError(Diagnostics.Index_signatures_are_incompatible);
}
return Ternary.False;
if (related) {
related &= eachPropertyRelatedTo(source, targetInfo.type, kind, reportErrors);
}
return related;
}
return Ternary.True;
if (reportErrors) {
reportError(Diagnostics.Index_signature_is_missing_in_type_0, typeToString(source));
}
return Ternary.False;
}
function numberIndexTypesRelatedTo(source: Type, originalSource: Type, target: Type, reportErrors: boolean): Ternary {
if (relation === identityRelation) {
return indexTypesIdenticalTo(IndexKind.Number, source, target);
}
const targetInfo = getIndexInfoOfType(target, IndexKind.Number);
if (targetInfo) {
if ((targetInfo.type.flags & TypeFlags.Any) && !(originalSource.flags & TypeFlags.Primitive)) {
// non-primitive assignment to any is always allowed, eg
// `var x: { [index: number]: any } = { property: 12 };`
return Ternary.True;
}
const sourceStringInfo = getIndexInfoOfType(source, IndexKind.String);
const sourceNumberInfo = getIndexInfoOfType(source, IndexKind.Number);
if (!(sourceStringInfo || sourceNumberInfo)) {
if (isObjectLiteralType(source)) {
return eachPropertyRelatedTo(source, targetInfo.type, /* numericPropertiesOnly*/ true, reportErrors);
}
if (reportErrors) {
reportError(Diagnostics.Index_signature_is_missing_in_type_0, typeToString(source));
}
return Ternary.False;
}
let related: Ternary;
if (sourceStringInfo && sourceNumberInfo) {
// If we know for sure we're testing both string and numeric index types then only report errors from the second one
related = isRelatedTo(sourceStringInfo.type, targetInfo.type, /*reportErrors*/ false) ||
isRelatedTo(sourceNumberInfo.type, targetInfo.type, reportErrors);
}
else {
related = isRelatedTo((sourceStringInfo || sourceNumberInfo).type, targetInfo.type, reportErrors);
}
if (!related) {
if (reportErrors) {
reportError(Diagnostics.Index_signatures_are_incompatible);
}
return Ternary.False;
}
return related;
}
return Ternary.True;
}
function indexTypesIdenticalTo(indexKind: IndexKind, source: Type, target: Type): Ternary {
function indexTypesIdenticalTo(source: Type, target: Type, indexKind: IndexKind): Ternary {
const targetInfo = getIndexInfoOfType(target, indexKind);
const sourceInfo = getIndexInfoOfType(source, indexKind);
if (!sourceInfo && !targetInfo) {