mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 08:11:30 -06:00
Primitives are not assignable to any-type indexers
`string/numberIndexTypesRelatedTo` needs to prevent primitives from being assignable to an indexer of type 'any'. However, these two functions take an apparent type, which no longer has the primitive flag set. I thought of three ways to provide this information: 1. Pass the original type into `string/numberIndexTypesRelatedTo` and check its flag. 2. Record a boolean `isPrimitive` before converting to the apparent type, and pass it to `string/numberIndexTypesRelatedTo`. 3. Create a helper function `isPrimitive` that takes the apparent type and compares it to globalString/Number/Boolean/ESSymbolType. I decided on (1) because it seems like the simplest and safest. But none of the options are elegant. Please suggest improvements.
This commit is contained in:
parent
21e30e0f59
commit
6798bd576b
@ -4895,7 +4895,7 @@ namespace ts {
|
||||
if (apparentType.flags & (TypeFlags.ObjectType | TypeFlags.Intersection) && target.flags & TypeFlags.ObjectType) {
|
||||
// Report structural errors only if we haven't reported any errors yet
|
||||
let reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo;
|
||||
if (result = objectTypeRelatedTo(apparentType, <ObjectType>target, reportStructuralErrors)) {
|
||||
if (result = objectTypeRelatedTo(apparentType, source, target, reportStructuralErrors)) {
|
||||
errorInfo = saveErrorInfo;
|
||||
return result;
|
||||
}
|
||||
@ -4917,7 +4917,7 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return objectTypeRelatedTo(<ObjectType>source, <ObjectType>target, /*reportErrors*/ false);
|
||||
return objectTypeRelatedTo(source, source, target, /*reportErrors*/ false);
|
||||
}
|
||||
if (source.flags & TypeFlags.TypeParameter && target.flags & TypeFlags.TypeParameter) {
|
||||
return typeParameterIdenticalTo(<TypeParameter>source, <TypeParameter>target);
|
||||
@ -5071,11 +5071,11 @@ namespace ts {
|
||||
// Third, check if both types are part of deeply nested chains of generic type instantiations and if so assume the types are
|
||||
// equal and infinitely expanding. Fourth, if we have reached a depth of 100 nested comparisons, assume we have runaway recursion
|
||||
// and issue an error. Otherwise, actually compare the structure of the two types.
|
||||
function objectTypeRelatedTo(source: Type, target: Type, reportErrors: boolean): Ternary {
|
||||
function objectTypeRelatedTo(apparentSource: Type, originalSource: Type, target: Type, reportErrors: boolean): Ternary {
|
||||
if (overflow) {
|
||||
return Ternary.False;
|
||||
}
|
||||
let id = relation !== identityRelation || source.id < target.id ? source.id + "," + target.id : target.id + "," + source.id;
|
||||
let id = relation !== identityRelation || apparentSource.id < target.id ? apparentSource.id + "," + target.id : target.id + "," + apparentSource.id;
|
||||
let related = relation[id];
|
||||
if (related !== undefined) {
|
||||
// If we computed this relation already and it was failed and reported, or if we're not being asked to elaborate
|
||||
@ -5102,28 +5102,28 @@ namespace ts {
|
||||
maybeStack = [];
|
||||
expandingFlags = 0;
|
||||
}
|
||||
sourceStack[depth] = source;
|
||||
sourceStack[depth] = apparentSource;
|
||||
targetStack[depth] = target;
|
||||
maybeStack[depth] = {};
|
||||
maybeStack[depth][id] = RelationComparisonResult.Succeeded;
|
||||
depth++;
|
||||
let saveExpandingFlags = expandingFlags;
|
||||
if (!(expandingFlags & 1) && isDeeplyNestedGeneric(source, sourceStack, depth)) expandingFlags |= 1;
|
||||
if (!(expandingFlags & 1) && isDeeplyNestedGeneric(apparentSource, sourceStack, depth)) expandingFlags |= 1;
|
||||
if (!(expandingFlags & 2) && isDeeplyNestedGeneric(target, targetStack, depth)) expandingFlags |= 2;
|
||||
let result: Ternary;
|
||||
if (expandingFlags === 3) {
|
||||
result = Ternary.Maybe;
|
||||
}
|
||||
else {
|
||||
result = propertiesRelatedTo(source, target, reportErrors);
|
||||
result = propertiesRelatedTo(apparentSource, target, reportErrors);
|
||||
if (result) {
|
||||
result &= signaturesRelatedTo(source, target, SignatureKind.Call, reportErrors);
|
||||
result &= signaturesRelatedTo(apparentSource, target, SignatureKind.Call, reportErrors);
|
||||
if (result) {
|
||||
result &= signaturesRelatedTo(source, target, SignatureKind.Construct, reportErrors);
|
||||
result &= signaturesRelatedTo(apparentSource, target, SignatureKind.Construct, reportErrors);
|
||||
if (result) {
|
||||
result &= stringIndexTypesRelatedTo(source, target, reportErrors);
|
||||
result &= stringIndexTypesRelatedTo(apparentSource, originalSource, target, reportErrors);
|
||||
if (result) {
|
||||
result &= numberIndexTypesRelatedTo(source, target, reportErrors);
|
||||
result &= numberIndexTypesRelatedTo(apparentSource, originalSource, target, reportErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5454,12 +5454,17 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
function stringIndexTypesRelatedTo(source: Type, target: Type, reportErrors: boolean): Ternary {
|
||||
function stringIndexTypesRelatedTo(source: Type, originalSource: Type, target: Type, reportErrors: boolean): Ternary {
|
||||
if (relation === identityRelation) {
|
||||
return indexTypesIdenticalTo(IndexKind.String, source, target);
|
||||
}
|
||||
let targetType = getIndexTypeOfType(target, IndexKind.String);
|
||||
if (targetType && !(targetType.flags & TypeFlags.Any)) {
|
||||
if (targetType) {
|
||||
if ((targetType.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;
|
||||
}
|
||||
let sourceType = getIndexTypeOfType(source, IndexKind.String);
|
||||
if (!sourceType) {
|
||||
if (reportErrors) {
|
||||
@ -5479,12 +5484,17 @@ namespace ts {
|
||||
return Ternary.True;
|
||||
}
|
||||
|
||||
function numberIndexTypesRelatedTo(source: Type, target: Type, reportErrors: boolean): Ternary {
|
||||
function numberIndexTypesRelatedTo(source: Type, originalSource: Type, target: Type, reportErrors: boolean): Ternary {
|
||||
if (relation === identityRelation) {
|
||||
return indexTypesIdenticalTo(IndexKind.Number, source, target);
|
||||
}
|
||||
let targetType = getIndexTypeOfType(target, IndexKind.Number);
|
||||
if (targetType && !(targetType.flags & TypeFlags.Any)) {
|
||||
if (targetType) {
|
||||
if ((targetType.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;
|
||||
}
|
||||
let sourceStringType = getIndexTypeOfType(source, IndexKind.String);
|
||||
let sourceNumberType = getIndexTypeOfType(source, IndexKind.Number);
|
||||
if (!(sourceStringType || sourceNumberType)) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user