mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-26 00:36:29 -05:00
Improved subtype compatibility for types of object literals
This commit is contained in:
@@ -66,8 +66,8 @@ module ts {
|
||||
var numberType = createIntrinsicType(TypeFlags.Number, "number");
|
||||
var booleanType = createIntrinsicType(TypeFlags.Boolean, "boolean");
|
||||
var voidType = createIntrinsicType(TypeFlags.Void, "void");
|
||||
var undefinedType = createIntrinsicType(TypeFlags.Undefined | TypeFlags.Unwidened, "undefined");
|
||||
var nullType = createIntrinsicType(TypeFlags.Null | TypeFlags.Unwidened, "null");
|
||||
var undefinedType = createIntrinsicType(TypeFlags.Undefined | TypeFlags.ContainsUndefined, "undefined");
|
||||
var nullType = createIntrinsicType(TypeFlags.Null | TypeFlags.ContainsUndefined, "null");
|
||||
var unknownType = createIntrinsicType(TypeFlags.Any, "unknown");
|
||||
var resolvingType = createIntrinsicType(TypeFlags.Any, "__resolving__");
|
||||
|
||||
@@ -2807,15 +2807,19 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
function getUnwidenedFlagOfTypes(types: Type[]): TypeFlags {
|
||||
return forEach(types, t => t.flags & TypeFlags.Unwidened) || 0;
|
||||
function getWideningFlagsOfTypes(types: Type[]): TypeFlags {
|
||||
var result: TypeFlags = 0;
|
||||
for (var i = 0; i < types.length; i++) {
|
||||
result |= types[i].flags;
|
||||
}
|
||||
return result & TypeFlags.RequiresWidening;
|
||||
}
|
||||
|
||||
function createTypeReference(target: GenericType, typeArguments: Type[]): TypeReference {
|
||||
var id = getTypeListId(typeArguments);
|
||||
var type = target.instantiations[id];
|
||||
if (!type) {
|
||||
var flags = TypeFlags.Reference | getUnwidenedFlagOfTypes(typeArguments);
|
||||
var flags = TypeFlags.Reference | getWideningFlagsOfTypes(typeArguments);
|
||||
type = target.instantiations[id] = <TypeReference>createObjectType(flags, target.symbol);
|
||||
type.target = target;
|
||||
type.typeArguments = typeArguments;
|
||||
@@ -3076,7 +3080,7 @@ module ts {
|
||||
var id = getTypeListId(sortedTypes);
|
||||
var type = unionTypes[id];
|
||||
if (!type) {
|
||||
type = unionTypes[id] = <UnionType>createObjectType(TypeFlags.Union | getUnwidenedFlagOfTypes(sortedTypes));
|
||||
type = unionTypes[id] = <UnionType>createObjectType(TypeFlags.Union | getWideningFlagsOfTypes(sortedTypes));
|
||||
type.types = sortedTypes;
|
||||
}
|
||||
return type;
|
||||
@@ -3692,12 +3696,13 @@ module ts {
|
||||
}
|
||||
var result = Ternary.True;
|
||||
var properties = getPropertiesOfObjectType(target);
|
||||
var requireOptionalProperties = relation === subtypeRelation && !(source.flags & TypeFlags.ObjectLiteral);
|
||||
for (var i = 0; i < properties.length; i++) {
|
||||
var targetProp = properties[i];
|
||||
var sourceProp = getPropertyOfType(source, targetProp.name);
|
||||
if (sourceProp !== targetProp) {
|
||||
if (!sourceProp) {
|
||||
if (relation === subtypeRelation || !(targetProp.flags & SymbolFlags.Optional)) {
|
||||
if (!(targetProp.flags & SymbolFlags.Optional) || requireOptionalProperties) {
|
||||
if (reportErrors) {
|
||||
reportError(Diagnostics.Property_0_is_missing_in_type_1, symbolToString(targetProp), typeToString(source));
|
||||
}
|
||||
@@ -4088,10 +4093,6 @@ module ts {
|
||||
errorMessageChainHead);
|
||||
}
|
||||
|
||||
function isTypeOfObjectLiteral(type: Type): boolean {
|
||||
return (type.flags & TypeFlags.Anonymous) && type.symbol && (type.symbol.flags & SymbolFlags.ObjectLiteral) ? true : false;
|
||||
}
|
||||
|
||||
function isArrayType(type: Type): boolean {
|
||||
return type.flags & TypeFlags.Reference && (<TypeReference>type).target === globalArrayType;
|
||||
}
|
||||
@@ -4104,13 +4105,18 @@ module ts {
|
||||
var properties = getPropertiesOfObjectType(type);
|
||||
var members: SymbolTable = {};
|
||||
forEach(properties, p => {
|
||||
var symbol = <TransientSymbol>createSymbol(p.flags | SymbolFlags.Transient, p.name);
|
||||
symbol.declarations = p.declarations;
|
||||
symbol.parent = p.parent;
|
||||
symbol.type = getWidenedType(getTypeOfSymbol(p));
|
||||
symbol.target = p;
|
||||
if (p.valueDeclaration) symbol.valueDeclaration = p.valueDeclaration;
|
||||
members[symbol.name] = symbol;
|
||||
var propType = getTypeOfSymbol(p);
|
||||
var widenedType = getWidenedType(propType);
|
||||
if (propType !== widenedType) {
|
||||
var symbol = <TransientSymbol>createSymbol(p.flags | SymbolFlags.Transient, p.name);
|
||||
symbol.declarations = p.declarations;
|
||||
symbol.parent = p.parent;
|
||||
symbol.type = getWidenedType(getTypeOfSymbol(p));
|
||||
symbol.target = p;
|
||||
if (p.valueDeclaration) symbol.valueDeclaration = p.valueDeclaration;
|
||||
p = symbol;
|
||||
}
|
||||
members[p.name] = p;
|
||||
});
|
||||
var stringIndexType = getIndexTypeOfType(type, IndexKind.String);
|
||||
var numberIndexType = getIndexTypeOfType(type, IndexKind.Number);
|
||||
@@ -4120,16 +4126,16 @@ module ts {
|
||||
}
|
||||
|
||||
function getWidenedType(type: Type): Type {
|
||||
if (type.flags & TypeFlags.Unwidened) {
|
||||
if (type.flags & TypeFlags.RequiresWidening) {
|
||||
if (type.flags & (TypeFlags.Undefined | TypeFlags.Null)) {
|
||||
return anyType;
|
||||
}
|
||||
if (type.flags & TypeFlags.ObjectLiteral) {
|
||||
return getWidenedTypeOfObjectLiteral(type);
|
||||
}
|
||||
if (type.flags & TypeFlags.Union) {
|
||||
return getUnionType(map((<UnionType>type).types, getWidenedType));
|
||||
}
|
||||
if (isTypeOfObjectLiteral(type)) {
|
||||
return getWidenedTypeOfObjectLiteral(type);
|
||||
}
|
||||
if (isArrayType(type)) {
|
||||
return createArrayType(getWidenedType((<TypeReference>type).typeArguments[0]));
|
||||
}
|
||||
@@ -4150,11 +4156,11 @@ module ts {
|
||||
if (isArrayType(type)) {
|
||||
return reportWideningErrorsInType((<TypeReference>type).typeArguments[0]);
|
||||
}
|
||||
if (isTypeOfObjectLiteral(type)) {
|
||||
if (type.flags & TypeFlags.ObjectLiteral) {
|
||||
var errorReported = false;
|
||||
forEach(getPropertiesOfObjectType(type), p => {
|
||||
var t = getTypeOfSymbol(p);
|
||||
if (t.flags & TypeFlags.Unwidened) {
|
||||
if (t.flags & TypeFlags.ContainsUndefined) {
|
||||
if (!reportWideningErrorsInType(t)) {
|
||||
error(p.valueDeclaration, Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, p.name, typeToString(getWidenedType(t)));
|
||||
}
|
||||
@@ -4198,7 +4204,7 @@ module ts {
|
||||
}
|
||||
|
||||
function reportErrorsFromWidening(declaration: Declaration, type: Type) {
|
||||
if (produceDiagnostics && compilerOptions.noImplicitAny && type.flags & TypeFlags.Unwidened) {
|
||||
if (produceDiagnostics && compilerOptions.noImplicitAny && type.flags & TypeFlags.ContainsUndefined) {
|
||||
// Report implicit any error within type if possible, otherwise report error on declaration
|
||||
if (!reportWideningErrorsInType(type)) {
|
||||
reportImplicitAnyError(declaration, type);
|
||||
@@ -5455,21 +5461,10 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
// If object literal is contextually (but not inferentially) typed, copy missing optional properties from
|
||||
// the contextual type such that the resulting type becomes a subtype in cases where only optional properties
|
||||
// were omitted. There is no need to create new property objects as nothing in them needs to change.
|
||||
if (contextualType && !isInferentialContext(contextualMapper)) {
|
||||
forEach(getPropertiesOfObjectType(contextualType), p => {
|
||||
if (p.flags & SymbolFlags.Optional && !hasProperty(properties, p.name)) {
|
||||
properties[p.name] = p;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var stringIndexType = getIndexType(IndexKind.String);
|
||||
var numberIndexType = getIndexType(IndexKind.Number);
|
||||
var result = createAnonymousType(node.symbol, properties, emptyArray, emptyArray, stringIndexType, numberIndexType);
|
||||
result.flags |= (typeFlags & TypeFlags.Unwidened);
|
||||
result.flags |= TypeFlags.ObjectLiteral | TypeFlags.ContainsLiteral | (typeFlags & TypeFlags.ContainsUndefined);
|
||||
return result;
|
||||
|
||||
function getIndexType(kind: IndexKind) {
|
||||
@@ -5485,7 +5480,9 @@ module ts {
|
||||
}
|
||||
}
|
||||
}
|
||||
return propTypes.length ? getUnionType(propTypes) : undefinedType;
|
||||
var result = propTypes.length ? getUnionType(propTypes) : undefinedType;
|
||||
typeFlags |= result.flags;
|
||||
return result;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -1283,12 +1283,15 @@ module ts {
|
||||
Union = 0x00004000, // Union
|
||||
Anonymous = 0x00008000, // Anonymous
|
||||
FromSignature = 0x00010000, // Created for signature assignment check
|
||||
Unwidened = 0x00020000, // Unwidened type (is or contains Undefined or Null type)
|
||||
ObjectLiteral = 0x00020000, // Originates in an object literal
|
||||
ContainsUndefined = 0x00040000, // Type is or contains Undefined or Null type
|
||||
ContainsLiteral = 0x00080000, // Type is or contains object literal type
|
||||
|
||||
Intrinsic = Any | String | Number | Boolean | Void | Undefined | Null,
|
||||
StringLike = String | StringLiteral,
|
||||
NumberLike = Number | Enum,
|
||||
ObjectType = Class | Interface | Reference | Tuple | Anonymous,
|
||||
RequiresWidening = ContainsUndefined | ContainsLiteral
|
||||
}
|
||||
|
||||
// Properties common to all types
|
||||
|
||||
Reference in New Issue
Block a user