Merge pull request #3622 from Microsoft/intersectionTypes

Intersection types
This commit is contained in:
Anders Hejlsberg 2015-07-06 12:58:28 -07:00
commit 71c6433514
36 changed files with 1548 additions and 194 deletions

View file

@ -140,6 +140,7 @@ namespace ts {
let tupleTypes: Map<TupleType> = {};
let unionTypes: Map<UnionType> = {};
let intersectionTypes: Map<IntersectionType> = {};
let stringLiteralTypes: Map<StringLiteralType> = {};
let emitExtends = false;
let emitDecorate = false;
@ -1575,8 +1576,8 @@ namespace ts {
else if (type.flags & TypeFlags.Tuple) {
writeTupleType(<TupleType>type);
}
else if (type.flags & TypeFlags.Union) {
writeUnionType(<UnionType>type, flags);
else if (type.flags & TypeFlags.UnionOrIntersection) {
writeUnionOrIntersectionType(<UnionOrIntersectionType>type, flags);
}
else if (type.flags & TypeFlags.Anonymous) {
writeAnonymousType(<ObjectType>type, flags);
@ -1595,16 +1596,16 @@ namespace ts {
}
}
function writeTypeList(types: Type[], union: boolean) {
function writeTypeList(types: Type[], delimiter: SyntaxKind) {
for (let i = 0; i < types.length; i++) {
if (i > 0) {
if (union) {
if (delimiter !== SyntaxKind.CommaToken) {
writeSpace(writer);
}
writePunctuation(writer, union ? SyntaxKind.BarToken : SyntaxKind.CommaToken);
writePunctuation(writer, delimiter);
writeSpace(writer);
}
writeType(types[i], union ? TypeFormatFlags.InElementType : TypeFormatFlags.None);
writeType(types[i], delimiter === SyntaxKind.CommaToken ? TypeFormatFlags.None : TypeFormatFlags.InElementType);
}
}
@ -1662,15 +1663,15 @@ namespace ts {
function writeTupleType(type: TupleType) {
writePunctuation(writer, SyntaxKind.OpenBracketToken);
writeTypeList(type.elementTypes, /*union*/ false);
writeTypeList(type.elementTypes, SyntaxKind.CommaToken);
writePunctuation(writer, SyntaxKind.CloseBracketToken);
}
function writeUnionType(type: UnionType, flags: TypeFormatFlags) {
function writeUnionOrIntersectionType(type: UnionOrIntersectionType, flags: TypeFormatFlags) {
if (flags & TypeFormatFlags.InElementType) {
writePunctuation(writer, SyntaxKind.OpenParenToken);
}
writeTypeList(type.types, /*union*/ true);
writeTypeList(type.types, type.flags & TypeFlags.Union ? SyntaxKind.BarToken : SyntaxKind.AmpersandToken);
if (flags & TypeFormatFlags.InElementType) {
writePunctuation(writer, SyntaxKind.CloseParenToken);
}
@ -1747,7 +1748,7 @@ namespace ts {
}
function writeLiteralType(type: ObjectType, flags: TypeFormatFlags) {
let resolved = resolveObjectOrUnionTypeMembers(type);
let resolved = resolveStructuredTypeMembers(type);
if (!resolved.properties.length && !resolved.stringIndexType && !resolved.numberIndexType) {
if (!resolved.callSignatures.length && !resolved.constructSignatures.length) {
writePunctuation(writer, SyntaxKind.OpenBraceToken);
@ -2082,6 +2083,7 @@ namespace ts {
case SyntaxKind.ArrayType:
case SyntaxKind.TupleType:
case SyntaxKind.UnionType:
case SyntaxKind.IntersectionType:
case SyntaxKind.ParenthesizedType:
return isDeclarationVisible(<Declaration>node.parent);
@ -2704,7 +2706,7 @@ namespace ts {
if (baseConstructorType.flags & TypeFlags.ObjectType) {
// Resolving the members of a class requires us to resolve the base class of that class.
// We force resolution here such that we catch circularities now.
resolveObjectOrUnionTypeMembers(baseConstructorType);
resolveStructuredTypeMembers(baseConstructorType);
}
if (!popTypeResolution()) {
error(type.symbol.valueDeclaration, Diagnostics._0_is_referenced_directly_or_indirectly_in_its_own_base_expression, symbolToString(type.symbol));
@ -3034,7 +3036,7 @@ namespace ts {
}
function resolveTupleTypeMembers(type: TupleType) {
let arrayType = resolveObjectOrUnionTypeMembers(createArrayType(getUnionType(type.elementTypes)));
let arrayType = resolveStructuredTypeMembers(createArrayType(getUnionType(type.elementTypes)));
let members = createTupleTypeMemberSymbols(type.elementTypes);
addInheritedMembers(members, arrayType.properties);
setObjectTypeMembers(type, members, arrayType.callSignatures, arrayType.constructSignatures, arrayType.stringIndexType, arrayType.numberIndexType);
@ -3100,6 +3102,26 @@ namespace ts {
setObjectTypeMembers(type, emptySymbols, callSignatures, constructSignatures, stringIndexType, numberIndexType);
}
function intersectTypes(type1: Type, type2: Type): Type {
return !type1 ? type2 : !type2 ? type1 : getIntersectionType([type1, type2]);
}
function resolveIntersectionTypeMembers(type: IntersectionType) {
// The members and properties collections are empty for intersection types. To get all properties of an
// intersection type use getPropertiesOfType (only the language service uses this).
let callSignatures: Signature[] = emptyArray;
let constructSignatures: Signature[] = emptyArray;
let stringIndexType: Type = undefined;
let numberIndexType: Type = undefined;
for (let t of type.types) {
callSignatures = concatenate(callSignatures, getSignaturesOfType(t, SignatureKind.Call));
constructSignatures = concatenate(constructSignatures, getSignaturesOfType(t, SignatureKind.Construct));
stringIndexType = intersectTypes(stringIndexType, getIndexTypeOfType(t, IndexKind.String));
numberIndexType = intersectTypes(numberIndexType, getIndexTypeOfType(t, IndexKind.Number));
}
setObjectTypeMembers(type, emptySymbols, callSignatures, constructSignatures, stringIndexType, numberIndexType);
}
function resolveAnonymousTypeMembers(type: ObjectType) {
let symbol = type.symbol;
let members: SymbolTable;
@ -3144,7 +3166,7 @@ namespace ts {
setObjectTypeMembers(type, members, callSignatures, constructSignatures, stringIndexType, numberIndexType);
}
function resolveObjectOrUnionTypeMembers(type: ObjectType): ResolvedType {
function resolveStructuredTypeMembers(type: ObjectType): ResolvedType {
if (!(<ResolvedType>type).members) {
if (type.flags & (TypeFlags.Class | TypeFlags.Interface)) {
resolveClassOrInterfaceMembers(<InterfaceType>type);
@ -3158,6 +3180,9 @@ namespace ts {
else if (type.flags & TypeFlags.Union) {
resolveUnionTypeMembers(<UnionType>type);
}
else if (type.flags & TypeFlags.Intersection) {
resolveIntersectionTypeMembers(<IntersectionType>type);
}
else {
resolveTypeReferenceMembers(<TypeReference>type);
}
@ -3168,16 +3193,16 @@ namespace ts {
// Return properties of an object type or an empty array for other types
function getPropertiesOfObjectType(type: Type): Symbol[] {
if (type.flags & TypeFlags.ObjectType) {
return resolveObjectOrUnionTypeMembers(<ObjectType>type).properties;
return resolveStructuredTypeMembers(<ObjectType>type).properties;
}
return emptyArray;
}
// If the given type is an object type and that type has a property by the given name, return
// the symbol for that property. Otherwise return undefined.
// If the given type is an object type and that type has a property by the given name,
// return the symbol for that property.Otherwise return undefined.
function getPropertyOfObjectType(type: Type, name: string): Symbol {
if (type.flags & TypeFlags.ObjectType) {
let resolved = resolveObjectOrUnionTypeMembers(<ObjectType>type);
let resolved = resolveStructuredTypeMembers(<ObjectType>type);
if (hasProperty(resolved.members, name)) {
let symbol = resolved.members[name];
if (symbolIsValue(symbol)) {
@ -3187,20 +3212,23 @@ namespace ts {
}
}
function getPropertiesOfUnionType(type: UnionType): Symbol[] {
let result: Symbol[] = [];
forEach(getPropertiesOfType(type.types[0]), prop => {
let unionProp = getPropertyOfUnionType(type, prop.name);
if (unionProp) {
result.push(unionProp);
function getPropertiesOfUnionOrIntersectionType(type: UnionOrIntersectionType): Symbol[] {
for (let current of type.types) {
for (let prop of getPropertiesOfType(current)) {
getPropertyOfUnionOrIntersectionType(type, prop.name);
}
});
return result;
// The properties of a union type are those that are present in all constituent types, so
// we only need to check the properties of the first type
if (type.flags & TypeFlags.Union) {
break;
}
}
return type.resolvedProperties ? symbolsToArray(type.resolvedProperties) : emptyArray;
}
function getPropertiesOfType(type: Type): Symbol[] {
type = getApparentType(type);
return type.flags & TypeFlags.Union ? getPropertiesOfUnionType(<UnionType>type) : getPropertiesOfObjectType(type);
return type.flags & TypeFlags.UnionOrIntersection ? getPropertiesOfUnionOrIntersectionType(<UnionType>type) : getPropertiesOfObjectType(type);
}
/**
@ -3235,24 +3263,33 @@ namespace ts {
return type;
}
function createUnionProperty(unionType: UnionType, name: string): Symbol {
let types = unionType.types;
function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: string): Symbol {
let types = containingType.types;
let props: Symbol[];
for (let current of types) {
let type = getApparentType(current);
if (type !== unknownType) {
let prop = getPropertyOfType(type, name);
if (!prop || getDeclarationFlagsFromSymbol(prop) & (NodeFlags.Private | NodeFlags.Protected)) {
if (prop && !(getDeclarationFlagsFromSymbol(prop) & (NodeFlags.Private | NodeFlags.Protected))) {
if (!props) {
props = [prop];
}
else if (!contains(props, prop)) {
props.push(prop);
}
}
else if (containingType.flags & TypeFlags.Union) {
// A union type requires the property to be present in all constituent types
return undefined;
}
if (!props) {
props = [prop];
}
else {
props.push(prop);
}
}
}
if (!props) {
return undefined;
}
if (props.length === 1) {
return props[0];
}
let propTypes: Type[] = [];
let declarations: Declaration[] = [];
for (let prop of props) {
@ -3261,19 +3298,19 @@ namespace ts {
}
propTypes.push(getTypeOfSymbol(prop));
}
let result = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient | SymbolFlags.UnionProperty, name);
result.unionType = unionType;
let result = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient | SymbolFlags.SyntheticProperty, name);
result.containingType = containingType;
result.declarations = declarations;
result.type = getUnionType(propTypes);
result.type = containingType.flags & TypeFlags.Union ? getUnionType(propTypes) : getIntersectionType(propTypes);
return result;
}
function getPropertyOfUnionType(type: UnionType, name: string): Symbol {
function getPropertyOfUnionOrIntersectionType(type: UnionOrIntersectionType, name: string): Symbol {
let properties = type.resolvedProperties || (type.resolvedProperties = {});
if (hasProperty(properties, name)) {
return properties[name];
}
let property = createUnionProperty(type, name);
let property = createUnionOrIntersectionProperty(type, name);
if (property) {
properties[name] = property;
}
@ -3286,7 +3323,7 @@ namespace ts {
function getPropertyOfType(type: Type, name: string): Symbol {
type = getApparentType(type);
if (type.flags & TypeFlags.ObjectType) {
let resolved = resolveObjectOrUnionTypeMembers(type);
let resolved = resolveStructuredTypeMembers(type);
if (hasProperty(resolved.members, name)) {
let symbol = resolved.members[name];
if (symbolIsValue(symbol)) {
@ -3301,15 +3338,15 @@ namespace ts {
}
return getPropertyOfObjectType(globalObjectType, name);
}
if (type.flags & TypeFlags.Union) {
return getPropertyOfUnionType(<UnionType>type, name);
if (type.flags & TypeFlags.UnionOrIntersection) {
return getPropertyOfUnionOrIntersectionType(<UnionOrIntersectionType>type, name);
}
return undefined;
}
function getSignaturesOfObjectOrUnionType(type: Type, kind: SignatureKind): Signature[] {
if (type.flags & (TypeFlags.ObjectType | TypeFlags.Union)) {
let resolved = resolveObjectOrUnionTypeMembers(<ObjectType>type);
function getSignaturesOfStructuredType(type: Type, kind: SignatureKind): Signature[] {
if (type.flags & TypeFlags.StructuredType) {
let resolved = resolveStructuredTypeMembers(<ObjectType>type);
return kind === SignatureKind.Call ? resolved.callSignatures : resolved.constructSignatures;
}
return emptyArray;
@ -3318,22 +3355,21 @@ namespace ts {
// Return the signatures of the given kind in the given type. Creates synthetic union signatures when necessary and
// maps primitive types and type parameters are to their apparent types.
function getSignaturesOfType(type: Type, kind: SignatureKind): Signature[] {
return getSignaturesOfObjectOrUnionType(getApparentType(type), kind);
return getSignaturesOfStructuredType(getApparentType(type), kind);
}
function typeHasCallOrConstructSignatures(type: Type): boolean {
let apparentType = getApparentType(type);
if (apparentType.flags & (TypeFlags.ObjectType | TypeFlags.Union)) {
let resolved = resolveObjectOrUnionTypeMembers(<ObjectType>type);
return resolved.callSignatures.length > 0
|| resolved.constructSignatures.length > 0;
if (apparentType.flags & TypeFlags.StructuredType) {
let resolved = resolveStructuredTypeMembers(<ObjectType>type);
return resolved.callSignatures.length > 0 || resolved.constructSignatures.length > 0;
}
return false;
}
function getIndexTypeOfObjectOrUnionType(type: Type, kind: IndexKind): Type {
if (type.flags & (TypeFlags.ObjectType | TypeFlags.Union)) {
let resolved = resolveObjectOrUnionTypeMembers(<ObjectType>type);
function getIndexTypeOfStructuredType(type: Type, kind: IndexKind): Type {
if (type.flags & TypeFlags.StructuredType) {
let resolved = resolveStructuredTypeMembers(<ObjectType>type);
return kind === IndexKind.String ? resolved.stringIndexType : resolved.numberIndexType;
}
}
@ -3341,7 +3377,7 @@ namespace ts {
// Return the index type of the given kind in the given type. Creates synthetic union index types when necessary and
// maps primitive types and type parameters are to their apparent types.
function getIndexTypeOfType(type: Type, kind: IndexKind): Type {
return getIndexTypeOfObjectOrUnionType(getApparentType(type), kind);
return getIndexTypeOfStructuredType(getApparentType(type), kind);
}
// Return list of type parameters with duplicates removed (duplicate identifier errors are generated in the actual
@ -3891,25 +3927,20 @@ namespace ts {
return links.resolvedType;
}
function addTypeToSortedSet(sortedSet: Type[], type: Type) {
if (type.flags & TypeFlags.Union) {
addTypesToSortedSet(sortedSet, (<UnionType>type).types);
function addTypeToSet(typeSet: Type[], type: Type, typeSetKind: TypeFlags) {
if (type.flags & typeSetKind) {
addTypesToSet(typeSet, (<UnionOrIntersectionType>type).types, typeSetKind);
}
else {
let i = 0;
let id = type.id;
while (i < sortedSet.length && sortedSet[i].id < id) {
i++;
}
if (i === sortedSet.length || sortedSet[i].id !== id) {
sortedSet.splice(i, 0, type);
}
else if (!contains(typeSet, type)) {
typeSet.push(type);
}
}
function addTypesToSortedSet(sortedTypes: Type[], types: Type[]) {
// Add the given types to the given type set. Order is preserved, duplicates are removed,
// and nested types of the given kind are flattened into the set.
function addTypesToSet(typeSet: Type[], types: Type[], typeSetKind: TypeFlags) {
for (let type of types) {
addTypeToSortedSet(sortedTypes, type);
addTypeToSet(typeSet, type, typeSetKind);
}
}
@ -3951,6 +3982,10 @@ namespace ts {
}
}
function compareTypeIds(type1: Type, type2: Type): number {
return type1.id - type2.id;
}
// The noSubtypeReduction flag is there because it isn't possible to always do subtype reduction. The flag
// is true when creating a union type from a type node and when instantiating a union type. In both of those
// cases subtype reduction has to be deferred to properly support recursive union types. For example, a
@ -3959,26 +3994,27 @@ namespace ts {
if (types.length === 0) {
return emptyObjectType;
}
let sortedTypes: Type[] = [];
addTypesToSortedSet(sortedTypes, types);
let typeSet: Type[] = [];
addTypesToSet(typeSet, types, TypeFlags.Union);
typeSet.sort(compareTypeIds);
if (noSubtypeReduction) {
if (containsTypeAny(sortedTypes)) {
if (containsTypeAny(typeSet)) {
return anyType;
}
removeAllButLast(sortedTypes, undefinedType);
removeAllButLast(sortedTypes, nullType);
removeAllButLast(typeSet, undefinedType);
removeAllButLast(typeSet, nullType);
}
else {
removeSubtypes(sortedTypes);
removeSubtypes(typeSet);
}
if (sortedTypes.length === 1) {
return sortedTypes[0];
if (typeSet.length === 1) {
return typeSet[0];
}
let id = getTypeListId(sortedTypes);
let id = getTypeListId(typeSet);
let type = unionTypes[id];
if (!type) {
type = unionTypes[id] = <UnionType>createObjectType(TypeFlags.Union | getWideningFlagsOfTypes(sortedTypes));
type.types = sortedTypes;
type = unionTypes[id] = <UnionType>createObjectType(TypeFlags.Union | getWideningFlagsOfTypes(typeSet));
type.types = typeSet;
type.reducedType = noSubtypeReduction ? undefined : type;
}
return type;
@ -4010,6 +4046,40 @@ namespace ts {
return links.resolvedType;
}
// We do not perform supertype reduction on intersection types. Intersection types are created only by the &
// type operator and we can't reduce those because we want to support recursive intersection types. For example,
// a type alias of the form "type List<T> = T & { next: List<T> }" cannot be reduced during its declaration.
// Also, unlike union types, the order of the constituent types is preserved in order that overload resolution
// for intersections of types with signatures can be deterministic.
function getIntersectionType(types: Type[]): Type {
if (types.length === 0) {
return emptyObjectType;
}
let typeSet: Type[] = [];
addTypesToSet(typeSet, types, TypeFlags.Intersection);
if (containsTypeAny(typeSet)) {
return anyType;
}
if (typeSet.length === 1) {
return typeSet[0];
}
let id = getTypeListId(typeSet);
let type = intersectionTypes[id];
if (!type) {
type = intersectionTypes[id] = <IntersectionType>createObjectType(TypeFlags.Intersection | getWideningFlagsOfTypes(typeSet));
type.types = typeSet;
}
return type;
}
function getTypeFromIntersectionTypeNode(node: IntersectionTypeNode): Type {
let links = getNodeLinks(node);
if (!links.resolvedType) {
links.resolvedType = getIntersectionType(map(node.types, getTypeFromTypeNode));
}
return links.resolvedType;
}
function getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node: Node): Type {
let links = getNodeLinks(node);
if (!links.resolvedType) {
@ -4067,6 +4137,8 @@ namespace ts {
return getTypeFromTupleTypeNode(<TupleTypeNode>node);
case SyntaxKind.UnionType:
return getTypeFromUnionTypeNode(<UnionTypeNode>node);
case SyntaxKind.IntersectionType:
return getTypeFromIntersectionTypeNode(<IntersectionTypeNode>node);
case SyntaxKind.ParenthesizedType:
return getTypeFromTypeNode((<ParenthesizedTypeNode>node).type);
case SyntaxKind.FunctionType:
@ -4254,6 +4326,9 @@ namespace ts {
if (type.flags & TypeFlags.Union) {
return getUnionType(instantiateList((<UnionType>type).types, mapper, instantiateType), /*noSubtypeReduction*/ true);
}
if (type.flags & TypeFlags.Intersection) {
return getIntersectionType(instantiateList((<IntersectionType>type).types, mapper, instantiateType));
}
}
return type;
}
@ -4294,7 +4369,7 @@ namespace ts {
function getTypeWithoutSignatures(type: Type): Type {
if (type.flags & TypeFlags.ObjectType) {
let resolved = resolveObjectOrUnionTypeMembers(<ObjectType>type);
let resolved = resolveStructuredTypeMembers(<ObjectType>type);
if (resolved.constructSignatures.length) {
let result = <ResolvedType>createObjectType(TypeFlags.Anonymous, type.symbol);
result.members = resolved.members;
@ -4414,37 +4489,10 @@ namespace ts {
}
}
let saveErrorInfo = errorInfo;
if (source.flags & TypeFlags.Union || target.flags & TypeFlags.Union) {
if (relation === identityRelation) {
if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union) {
if (result = unionTypeRelatedToUnionType(<UnionType>source, <UnionType>target)) {
if (result &= unionTypeRelatedToUnionType(<UnionType>target, <UnionType>source)) {
return result;
}
}
}
else if (source.flags & TypeFlags.Union) {
if (result = unionTypeRelatedToType(<UnionType>source, target, reportErrors)) {
return result;
}
}
else {
if (result = unionTypeRelatedToType(<UnionType>target, source, reportErrors)) {
return result;
}
}
}
else {
if (source.flags & TypeFlags.Union) {
if (result = unionTypeRelatedToType(<UnionType>source, target, reportErrors)) {
return result;
}
}
else {
if (result = typeRelatedToUnionType(source, <UnionType>target, reportErrors)) {
return result;
}
}
if (source.flags & TypeFlags.Reference && target.flags & TypeFlags.Reference && (<TypeReference>source).target === (<TypeReference>target).target) {
// We have type references to same target type, see if relationship holds for all type arguments
if (result = typesRelatedTo((<TypeReference>source).typeArguments, (<TypeReference>target).typeArguments, reportErrors)) {
return result;
}
}
else if (source.flags & TypeFlags.TypeParameter && target.flags & TypeFlags.TypeParameter) {
@ -4452,10 +4500,43 @@ namespace ts {
return result;
}
}
else if (source.flags & TypeFlags.Reference && target.flags & TypeFlags.Reference && (<TypeReference>source).target === (<TypeReference>target).target) {
// We have type references to same target type, see if relationship holds for all type arguments
if (result = typesRelatedTo((<TypeReference>source).typeArguments, (<TypeReference>target).typeArguments, reportErrors)) {
return result;
else if (relation !== identityRelation) {
// Note that the "each" checks must precede the "some" checks to produce the correct results
if (source.flags & TypeFlags.Union) {
if (result = eachTypeRelatedToType(<UnionType>source, target, reportErrors)) {
return result;
}
}
else if (target.flags & TypeFlags.Intersection) {
if (result = typeRelatedToEachType(source, <IntersectionType>target, reportErrors)) {
return result;
}
}
else {
// It is necessary to try "each" checks on both sides because there may be nested "some" checks
// on either side that need to be prioritized. For example, A | B = (A | B) & (C | D) or
// A & B = (A & B) | (C & D).
if (source.flags & TypeFlags.Intersection) {
// If target is a union type the following check will report errors so we suppress them here
if (result = someTypeRelatedToType(<IntersectionType>source, target, reportErrors && !(target.flags & TypeFlags.Union))) {
return result;
}
}
if (target.flags & TypeFlags.Union) {
if (result = typeRelatedToSomeType(source, <UnionType>target, reportErrors)) {
return result;
}
}
}
}
else {
if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union ||
source.flags & TypeFlags.Intersection && target.flags & TypeFlags.Intersection) {
if (result = eachTypeRelatedToSomeType(<UnionOrIntersectionType>source, <UnionOrIntersectionType>target)) {
if (result &= eachTypeRelatedToSomeType(<UnionOrIntersectionType>target, <UnionOrIntersectionType>source)) {
return result;
}
}
}
}
@ -4463,17 +4544,20 @@ namespace ts {
// it may hold in a structural comparison.
// Report structural errors only if we haven't reported any errors yet
let reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo;
// identity relation does not use apparent type
// Identity relation does not use apparent type
let sourceOrApparentType = relation === identityRelation ? source : getApparentType(source);
if (sourceOrApparentType.flags & TypeFlags.ObjectType && target.flags & TypeFlags.ObjectType) {
// In a check of the form X = A & B, we will have previously checked if A relates to X or B relates
// to X. Failing both of those we want to check if the aggregation of A and B's members structurally
// relates to X. Thus, we include intersection types on the source side here.
if (sourceOrApparentType.flags & (TypeFlags.ObjectType | TypeFlags.Intersection) && target.flags & TypeFlags.ObjectType) {
if (result = objectTypeRelatedTo(sourceOrApparentType, <ObjectType>target, reportStructuralErrors)) {
errorInfo = saveErrorInfo;
return result;
}
}
else if (source.flags & TypeFlags.TypeParameter && sourceOrApparentType.flags & TypeFlags.Union) {
else if (source.flags & TypeFlags.TypeParameter && sourceOrApparentType.flags & TypeFlags.UnionOrIntersection) {
// We clear the errors first because the following check often gives a better error than
// the union comparison above if it is applicable.
// the union or intersection comparison above if it is applicable.
errorInfo = saveErrorInfo;
if (result = isRelatedTo(sourceOrApparentType, target, reportErrors)) {
return result;
@ -4493,11 +4577,11 @@ namespace ts {
return Ternary.False;
}
function unionTypeRelatedToUnionType(source: UnionType, target: UnionType): Ternary {
function eachTypeRelatedToSomeType(source: UnionOrIntersectionType, target: UnionOrIntersectionType): Ternary {
let result = Ternary.True;
let sourceTypes = source.types;
for (let sourceType of sourceTypes) {
let related = typeRelatedToUnionType(sourceType, target, false);
let related = typeRelatedToSomeType(sourceType, target, false);
if (!related) {
return Ternary.False;
}
@ -4506,7 +4590,7 @@ namespace ts {
return result;
}
function typeRelatedToUnionType(source: Type, target: UnionType, reportErrors: boolean): Ternary {
function typeRelatedToSomeType(source: Type, target: UnionOrIntersectionType, reportErrors: boolean): Ternary {
let targetTypes = target.types;
for (let i = 0, len = targetTypes.length; i < len; i++) {
let related = isRelatedTo(source, targetTypes[i], reportErrors && i === len - 1);
@ -4517,7 +4601,31 @@ namespace ts {
return Ternary.False;
}
function unionTypeRelatedToType(source: UnionType, target: Type, reportErrors: boolean): Ternary {
function typeRelatedToEachType(source: Type, target: UnionOrIntersectionType, reportErrors: boolean): Ternary {
let result = Ternary.True;
let targetTypes = target.types;
for (let targetType of targetTypes) {
let related = isRelatedTo(source, targetType, reportErrors);
if (!related) {
return Ternary.False;
}
result &= related;
}
return result;
}
function someTypeRelatedToType(source: UnionOrIntersectionType, target: Type, reportErrors: boolean): Ternary {
let sourceTypes = source.types;
for (let i = 0, len = sourceTypes.length; i < len; i++) {
let related = isRelatedTo(sourceTypes[i], target, reportErrors && i === len - 1);
if (related) {
return related;
}
}
return Ternary.False;
}
function eachTypeRelatedToType(source: UnionOrIntersectionType, target: Type, reportErrors: boolean): Ternary {
let result = Ternary.True;
let sourceTypes = source.types;
for (let sourceType of sourceTypes) {
@ -4572,7 +4680,7 @@ 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: ObjectType, target: ObjectType, reportErrors: boolean): Ternary {
function objectTypeRelatedTo(source: Type, target: Type, reportErrors: boolean): Ternary {
if (overflow) {
return Ternary.False;
}
@ -4647,7 +4755,7 @@ namespace ts {
return result;
}
function propertiesRelatedTo(source: ObjectType, target: ObjectType, reportErrors: boolean): Ternary {
function propertiesRelatedTo(source: Type, target: Type, reportErrors: boolean): Ternary {
if (relation === identityRelation) {
return propertiesIdenticalTo(source, target);
}
@ -4731,7 +4839,10 @@ namespace ts {
return result;
}
function propertiesIdenticalTo(source: ObjectType, target: ObjectType): Ternary {
function propertiesIdenticalTo(source: Type, target: Type): Ternary {
if (!(source.flags & TypeFlags.ObjectType && target.flags & TypeFlags.ObjectType)) {
return Ternary.False;
}
let sourceProperties = getPropertiesOfObjectType(source);
let targetProperties = getPropertiesOfObjectType(target);
if (sourceProperties.length !== targetProperties.length) {
@ -4752,7 +4863,7 @@ namespace ts {
return result;
}
function signaturesRelatedTo(source: ObjectType, target: ObjectType, kind: SignatureKind, reportErrors: boolean): Ternary {
function signaturesRelatedTo(source: Type, target: Type, kind: SignatureKind, reportErrors: boolean): Ternary {
if (relation === identityRelation) {
return signaturesIdenticalTo(source, target, kind);
}
@ -4878,7 +4989,7 @@ namespace ts {
return result & isRelatedTo(s, t, reportErrors);
}
function signaturesIdenticalTo(source: ObjectType, target: ObjectType, kind: SignatureKind): Ternary {
function signaturesIdenticalTo(source: Type, target: Type, kind: SignatureKind): Ternary {
let sourceSignatures = getSignaturesOfType(source, kind);
let targetSignatures = getSignaturesOfType(target, kind);
if (sourceSignatures.length !== targetSignatures.length) {
@ -4895,7 +5006,7 @@ namespace ts {
return result;
}
function stringIndexTypesRelatedTo(source: ObjectType, target: ObjectType, reportErrors: boolean): Ternary {
function stringIndexTypesRelatedTo(source: Type, target: Type, reportErrors: boolean): Ternary {
if (relation === identityRelation) {
return indexTypesIdenticalTo(IndexKind.String, source, target);
}
@ -4920,7 +5031,7 @@ namespace ts {
return Ternary.True;
}
function numberIndexTypesRelatedTo(source: ObjectType, target: ObjectType, reportErrors: boolean): Ternary {
function numberIndexTypesRelatedTo(source: Type, target: Type, reportErrors: boolean): Ternary {
if (relation === identityRelation) {
return indexTypesIdenticalTo(IndexKind.Number, source, target);
}
@ -4953,7 +5064,7 @@ namespace ts {
return Ternary.True;
}
function indexTypesIdenticalTo(indexKind: IndexKind, source: ObjectType, target: ObjectType): Ternary {
function indexTypesIdenticalTo(indexKind: IndexKind, source: Type, target: Type): Ternary {
let targetType = getIndexTypeOfType(target, indexKind);
let sourceType = getIndexTypeOfType(source, indexKind);
if (!sourceType && !targetType) {
@ -5337,11 +5448,11 @@ namespace ts {
inferFromTypes(sourceTypes[i], targetTypes[i]);
}
}
else if (target.flags & TypeFlags.Union) {
let targetTypes = (<UnionType>target).types;
else if (target.flags & TypeFlags.UnionOrIntersection) {
let targetTypes = (<UnionOrIntersectionType>target).types;
let typeParameterCount = 0;
let typeParameter: TypeParameter;
// First infer to each type in union that isn't a type parameter
// First infer to each type in union or intersection that isn't a type parameter
for (let t of targetTypes) {
if (t.flags & TypeFlags.TypeParameter && contains(context.typeParameters, t)) {
typeParameter = <TypeParameter>t;
@ -5351,16 +5462,19 @@ namespace ts {
inferFromTypes(source, t);
}
}
// If union contains a single naked type parameter, make a secondary inference to that type parameter
if (typeParameterCount === 1) {
// Next, if target is a union type containing a single naked type parameter, make a
// secondary inference to that type parameter. We don't do this for intersection types
// because in a target type like Foo & T we don't know how which parts of the source type
// should be matched by Foo and which should be inferred to T.
if (target.flags & TypeFlags.Union && typeParameterCount === 1) {
inferiority++;
inferFromTypes(source, typeParameter);
inferiority--;
}
}
else if (source.flags & TypeFlags.Union) {
// Source is a union type, infer from each consituent type
let sourceTypes = (<UnionType>source).types;
else if (source.flags & TypeFlags.UnionOrIntersection) {
// Source is a union or intersection type, infer from each consituent type
let sourceTypes = (<UnionOrIntersectionType>source).types;
for (let sourceType of sourceTypes) {
inferFromTypes(sourceType, target);
}
@ -6343,13 +6457,13 @@ namespace ts {
function getTypeOfPropertyOfContextualType(type: Type, name: string) {
return applyToContextualType(type, t => {
let prop = getPropertyOfObjectType(t, name);
let prop = t.flags & TypeFlags.StructuredType ? getPropertyOfType(t, name) : undefined;
return prop ? getTypeOfSymbol(prop) : undefined;
});
}
function getIndexTypeOfContextualType(type: Type, kind: IndexKind) {
return applyToContextualType(type, t => getIndexTypeOfObjectOrUnionType(t, kind));
return applyToContextualType(type, t => getIndexTypeOfStructuredType(t, kind));
}
// Return true if the given contextual type is a tuple-like type
@ -6359,7 +6473,7 @@ namespace ts {
// Return true if the given contextual type provides an index signature of the given kind
function contextualTypeHasIndexSignature(type: Type, kind: IndexKind): boolean {
return !!(type.flags & TypeFlags.Union ? forEach((<UnionType>type).types, t => getIndexTypeOfObjectOrUnionType(t, kind)) : getIndexTypeOfObjectOrUnionType(type, kind));
return !!(type.flags & TypeFlags.Union ? forEach((<UnionType>type).types, t => getIndexTypeOfStructuredType(t, kind)) : getIndexTypeOfStructuredType(type, kind));
}
// In an object literal contextually typed by a type T, the contextual type of a property assignment is the type of
@ -6496,7 +6610,7 @@ namespace ts {
// If the given type is an object or union type, if that type has a single signature, and if
// that signature is non-generic, return the signature. Otherwise return undefined.
function getNonGenericSignature(type: Type): Signature {
let signatures = getSignaturesOfObjectOrUnionType(type, SignatureKind.Call);
let signatures = getSignaturesOfStructuredType(type, SignatureKind.Call);
if (signatures.length === 1) {
let signature = signatures[0];
if (!signature.typeParameters) {
@ -6538,7 +6652,7 @@ namespace ts {
// The signature set of all constituent type with call signatures should match
// So number of signatures allowed is either 0 or 1
if (signatureList &&
getSignaturesOfObjectOrUnionType(current, SignatureKind.Call).length > 1) {
getSignaturesOfStructuredType(current, SignatureKind.Call).length > 1) {
return undefined;
}
@ -7691,7 +7805,7 @@ namespace ts {
// If type has a single call signature and no other members, return that signature. Otherwise, return undefined.
function getSingleCallSignature(type: Type): Signature {
if (type.flags & TypeFlags.ObjectType) {
let resolved = resolveObjectOrUnionTypeMembers(<ObjectType>type);
let resolved = resolveStructuredTypeMembers(<ObjectType>type);
if (resolved.callSignatures.length === 1 && resolved.constructSignatures.length === 0 &&
resolved.properties.length === 0 && !resolved.stringIndexType && !resolved.numberIndexType) {
return resolved.callSignatures[0];
@ -9131,8 +9245,8 @@ namespace ts {
if (type.flags & kind) {
return true;
}
if (type.flags & TypeFlags.Union) {
let types = (<UnionType>type).types;
if (type.flags & TypeFlags.UnionOrIntersection) {
let types = (<UnionOrIntersectionType>type).types;
for (let current of types) {
if (current.flags & kind) {
return true;
@ -9143,13 +9257,13 @@ namespace ts {
return false;
}
// Return true if type has the given flags, or is a union type composed of types that all have those flags.
// Return true if type has the given flags, or is a union or intersection type composed of types that all have those flags.
function allConstituentTypesHaveKind(type: Type, kind: TypeFlags): boolean {
if (type.flags & kind) {
return true;
}
if (type.flags & TypeFlags.Union) {
let types = (<UnionType>type).types;
if (type.flags & TypeFlags.UnionOrIntersection) {
let types = (<UnionOrIntersectionType>type).types;
for (let current of types) {
if (!(current.flags & kind)) {
return false;
@ -10174,7 +10288,7 @@ namespace ts {
forEach(node.elementTypes, checkSourceElement);
}
function checkUnionType(node: UnionTypeNode) {
function checkUnionOrIntersectionType(node: UnionOrIntersectionTypeNode) {
forEach(node.types, checkSourceElement);
}
@ -12951,7 +13065,8 @@ namespace ts {
case SyntaxKind.TupleType:
return checkTupleType(<TupleTypeNode>node);
case SyntaxKind.UnionType:
return checkUnionType(<UnionTypeNode>node);
case SyntaxKind.IntersectionType:
return checkUnionOrIntersectionType(<UnionOrIntersectionTypeNode>node);
case SyntaxKind.ParenthesizedType:
return checkSourceElement((<ParenthesizedTypeNode>node).type);
case SyntaxKind.FunctionDeclaration:
@ -13593,10 +13708,10 @@ namespace ts {
}
function getRootSymbols(symbol: Symbol): Symbol[] {
if (symbol.flags & SymbolFlags.UnionProperty) {
if (symbol.flags & SymbolFlags.SyntheticProperty) {
let symbols: Symbol[] = [];
let name = symbol.name;
forEach(getSymbolLinks(symbol).unionType.types, t => {
forEach(getSymbolLinks(symbol).containingType.types, t => {
symbols.push(getPropertyOfType(t, name));
});
return symbols;
@ -13893,6 +14008,7 @@ namespace ts {
case SyntaxKind.TypeQuery:
case SyntaxKind.TypeLiteral:
case SyntaxKind.UnionType:
case SyntaxKind.IntersectionType:
case SyntaxKind.AnyKeyword:
break;
default:

View file

@ -340,6 +340,8 @@ namespace ts {
return emitTupleType(<TupleTypeNode>type);
case SyntaxKind.UnionType:
return emitUnionType(<UnionTypeNode>type);
case SyntaxKind.IntersectionType:
return emitIntersectionType(<IntersectionTypeNode>type);
case SyntaxKind.ParenthesizedType:
return emitParenType(<ParenthesizedTypeNode>type);
case SyntaxKind.FunctionType:
@ -416,6 +418,10 @@ namespace ts {
emitSeparatedList(type.types, " | ", emitType);
}
function emitIntersectionType(type: IntersectionTypeNode) {
emitSeparatedList(type.types, " & ", emitType);
}
function emitParenType(type: ParenthesizedTypeNode) {
write("(");
emitType(type.type);

View file

@ -115,7 +115,8 @@ namespace ts {
case SyntaxKind.TupleType:
return visitNodes(cbNodes, (<TupleTypeNode>node).elementTypes);
case SyntaxKind.UnionType:
return visitNodes(cbNodes, (<UnionTypeNode>node).types);
case SyntaxKind.IntersectionType:
return visitNodes(cbNodes, (<UnionOrIntersectionTypeNode>node).types);
case SyntaxKind.ParenthesizedType:
return visitNode(cbNode, (<ParenthesizedTypeNode>node).type);
case SyntaxKind.ObjectBindingPattern:
@ -2401,22 +2402,30 @@ namespace ts {
return type;
}
function parseUnionTypeOrHigher(): TypeNode {
let type = parseArrayTypeOrHigher();
if (token === SyntaxKind.BarToken) {
function parseUnionOrIntersectionType(kind: SyntaxKind, parseConstituentType: () => TypeNode, operator: SyntaxKind): TypeNode {
let type = parseConstituentType();
if (token === operator) {
let types = <NodeArray<TypeNode>>[type];
types.pos = type.pos;
while (parseOptional(SyntaxKind.BarToken)) {
types.push(parseArrayTypeOrHigher());
while (parseOptional(operator)) {
types.push(parseConstituentType());
}
types.end = getNodeEnd();
let node = <UnionTypeNode>createNode(SyntaxKind.UnionType, type.pos);
let node = <UnionOrIntersectionTypeNode>createNode(kind, type.pos);
node.types = types;
type = finishNode(node);
}
return type;
}
function parseIntersectionTypeOrHigher(): TypeNode {
return parseUnionOrIntersectionType(SyntaxKind.IntersectionType, parseArrayTypeOrHigher, SyntaxKind.AmpersandToken);
}
function parseUnionTypeOrHigher(): TypeNode {
return parseUnionOrIntersectionType(SyntaxKind.UnionType, parseIntersectionTypeOrHigher, SyntaxKind.BarToken);
}
function isStartOfFunctionType(): boolean {
if (token === SyntaxKind.LessThanToken) {
return true;

View file

@ -191,6 +191,7 @@ namespace ts {
ArrayType,
TupleType,
UnionType,
IntersectionType,
ParenthesizedType,
// Binding patterns
ObjectBindingPattern,
@ -667,10 +668,14 @@ namespace ts {
elementTypes: NodeArray<TypeNode>;
}
export interface UnionTypeNode extends TypeNode {
export interface UnionOrIntersectionTypeNode extends TypeNode {
types: NodeArray<TypeNode>;
}
export interface UnionTypeNode extends UnionOrIntersectionTypeNode { }
export interface IntersectionTypeNode extends UnionOrIntersectionTypeNode { }
export interface ParenthesizedTypeNode extends TypeNode {
type: TypeNode;
}
@ -1573,7 +1578,7 @@ namespace ts {
Merged = 0x02000000, // Merged symbol (created during program binding)
Transient = 0x04000000, // Transient symbol (created during type check)
Prototype = 0x08000000, // Prototype property (no source representation)
UnionProperty = 0x10000000, // Property in union type
SyntheticProperty = 0x10000000, // Property in union or intersection type
Optional = 0x20000000, // Optional property
ExportStar = 0x40000000, // Export * declaration
@ -1652,7 +1657,7 @@ namespace ts {
instantiations?: Map<Type>; // Instantiations of generic type alias (undefined if non-generic)
mapper?: TypeMapper; // Type mapper for instantiation alias
referenced?: boolean; // True if alias symbol has been referenced as a value
unionType?: UnionType; // Containing union type for union property
containingType?: UnionOrIntersectionType; // Containing union or intersection type for synthetic property
resolvedExports?: SymbolTable; // Resolved exports of module
exportsChecked?: boolean; // True if exports of external module have been checked
isNestedRedeclaration?: boolean; // True if symbol is block scoped redeclaration
@ -1721,17 +1726,18 @@ namespace ts {
Interface = 0x00000800, // Interface
Reference = 0x00001000, // Generic type reference
Tuple = 0x00002000, // Tuple
Union = 0x00004000, // Union
Anonymous = 0x00008000, // Anonymous
Instantiated = 0x00010000, // Instantiated anonymous type
Union = 0x00004000, // Union (T | U)
Intersection = 0x00008000, // Intersection (T & U)
Anonymous = 0x00010000, // Anonymous
Instantiated = 0x00020000, // Instantiated anonymous type
/* @internal */
FromSignature = 0x00020000, // Created for signature assignment check
ObjectLiteral = 0x00040000, // Originates in an object literal
FromSignature = 0x00040000, // Created for signature assignment check
ObjectLiteral = 0x00080000, // Originates in an object literal
/* @internal */
ContainsUndefinedOrNull = 0x00080000, // Type is or contains Undefined or Null type
ContainsUndefinedOrNull = 0x00100000, // Type is or contains Undefined or Null type
/* @internal */
ContainsObjectLiteral = 0x00100000, // Type is or contains object literal type
ESSymbol = 0x00200000, // Type of symbol primitive introduced in ES6
ContainsObjectLiteral = 0x00200000, // Type is or contains object literal type
ESSymbol = 0x00400000, // Type of symbol primitive introduced in ES6
/* @internal */
Intrinsic = Any | String | Number | Boolean | ESSymbol | Void | Undefined | Null,
@ -1740,6 +1746,8 @@ namespace ts {
StringLike = String | StringLiteral,
NumberLike = Number | Enum,
ObjectType = Class | Interface | Reference | Tuple | Anonymous,
UnionOrIntersection = Union | Intersection,
StructuredType = ObjectType | Union | Intersection,
/* @internal */
RequiresWidening = ContainsUndefinedOrNull | ContainsObjectLiteral
}
@ -1799,7 +1807,7 @@ namespace ts {
baseArrayType: TypeReference; // Array<T> where T is best common type of element types
}
export interface UnionType extends Type {
export interface UnionOrIntersectionType extends Type {
types: Type[]; // Constituent types
/* @internal */
reducedType: Type; // Reduced union type (all subtypes removed)
@ -1807,9 +1815,13 @@ namespace ts {
resolvedProperties: SymbolTable; // Cache of resolved properties
}
export interface UnionType extends UnionOrIntersectionType { }
export interface IntersectionType extends UnionOrIntersectionType { }
/* @internal */
// Resolved object or union type
export interface ResolvedType extends ObjectType, UnionType {
// Resolved object, union, or intersection type
export interface ResolvedType extends ObjectType, UnionOrIntersectionType {
members: SymbolTable; // Properties by name
properties: Symbol[]; // Properties
callSignatures: Signature[]; // Call signatures of type

View file

@ -3689,7 +3689,7 @@ namespace ts {
if (flags & SymbolFlags.Constructor) return ScriptElementKind.constructorImplementationElement;
if (flags & SymbolFlags.Property) {
if (flags & SymbolFlags.UnionProperty) {
if (flags & SymbolFlags.SyntheticProperty) {
// If union property is result of union of non method (property/accessors/variables), it is labeled as property
let unionPropertyKind = forEach(typeChecker.getRootSymbols(symbol), rootSymbol => {
let rootSymbolFlags = rootSymbol.getFlags();
@ -5159,7 +5159,7 @@ namespace ts {
// if this symbol is visible from its parent container, e.g. exported, then bail out
// if symbol correspond to the union property - bail out
if (symbol.parent || (symbol.flags & SymbolFlags.UnionProperty)) {
if (symbol.parent || (symbol.flags & SymbolFlags.SyntheticProperty)) {
return undefined;
}

View file

@ -75,26 +75,26 @@ function delint(sourceFile) {
delintNode(sourceFile);
function delintNode(node) {
switch (node.kind) {
case 195 /* ForStatement */:
case 196 /* ForInStatement */:
case 194 /* WhileStatement */:
case 193 /* DoStatement */:
if (node.statement.kind !== 188 /* Block */) {
case 196 /* ForStatement */:
case 197 /* ForInStatement */:
case 195 /* WhileStatement */:
case 194 /* DoStatement */:
if (node.statement.kind !== 189 /* Block */) {
report(node, "A looping statement's contents should be wrapped in a block body.");
}
break;
case 192 /* IfStatement */:
case 193 /* IfStatement */:
var ifStatement = node;
if (ifStatement.thenStatement.kind !== 188 /* Block */) {
if (ifStatement.thenStatement.kind !== 189 /* Block */) {
report(ifStatement.thenStatement, "An if statement's contents should be wrapped in a block body.");
}
if (ifStatement.elseStatement &&
ifStatement.elseStatement.kind !== 188 /* Block */ &&
ifStatement.elseStatement.kind !== 192 /* IfStatement */) {
ifStatement.elseStatement.kind !== 189 /* Block */ &&
ifStatement.elseStatement.kind !== 193 /* IfStatement */) {
report(ifStatement.elseStatement, "An else statement's contents should be wrapped in a block body.");
}
break;
case 177 /* BinaryExpression */:
case 178 /* BinaryExpression */:
var op = node.operatorToken.kind;
if (op === 29 /* EqualsEqualsToken */ || op == 30 /* ExclamationEqualsToken */) {
report(node, "Use '===' and '!=='.");

View file

@ -0,0 +1,14 @@
//// [contextualIntersectionType.ts]
var x: { a: (s: string) => string } & { b: (n: number) => number };
x = {
a: s => s,
b: n => n
};
//// [contextualIntersectionType.js]
var x;
x = {
a: function (s) { return s; },
b: function (n) { return n; }
};

View file

@ -0,0 +1,23 @@
=== tests/cases/conformance/types/intersection/contextualIntersectionType.ts ===
var x: { a: (s: string) => string } & { b: (n: number) => number };
>x : Symbol(x, Decl(contextualIntersectionType.ts, 0, 3))
>a : Symbol(a, Decl(contextualIntersectionType.ts, 0, 8))
>s : Symbol(s, Decl(contextualIntersectionType.ts, 0, 13))
>b : Symbol(b, Decl(contextualIntersectionType.ts, 0, 39))
>n : Symbol(n, Decl(contextualIntersectionType.ts, 0, 44))
x = {
>x : Symbol(x, Decl(contextualIntersectionType.ts, 0, 3))
a: s => s,
>a : Symbol(a, Decl(contextualIntersectionType.ts, 1, 5))
>s : Symbol(s, Decl(contextualIntersectionType.ts, 2, 6))
>s : Symbol(s, Decl(contextualIntersectionType.ts, 2, 6))
b: n => n
>b : Symbol(b, Decl(contextualIntersectionType.ts, 2, 14))
>n : Symbol(n, Decl(contextualIntersectionType.ts, 3, 6))
>n : Symbol(n, Decl(contextualIntersectionType.ts, 3, 6))
};

View file

@ -0,0 +1,27 @@
=== tests/cases/conformance/types/intersection/contextualIntersectionType.ts ===
var x: { a: (s: string) => string } & { b: (n: number) => number };
>x : { a: (s: string) => string; } & { b: (n: number) => number; }
>a : (s: string) => string
>s : string
>b : (n: number) => number
>n : number
x = {
>x = { a: s => s, b: n => n} : { a: (s: string) => string; b: (n: number) => number; }
>x : { a: (s: string) => string; } & { b: (n: number) => number; }
>{ a: s => s, b: n => n} : { a: (s: string) => string; b: (n: number) => number; }
a: s => s,
>a : (s: string) => string
>s => s : (s: string) => string
>s : string
>s : string
b: n => n
>b : (n: number) => number
>n => n : (n: number) => number
>n : number
>n : number
};

View file

@ -0,0 +1,162 @@
tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(19,1): error TS2322: Type 'A' is not assignable to type 'A & B'.
Type 'A' is not assignable to type 'B'.
tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(20,1): error TS2322: Type 'B' is not assignable to type 'A & B'.
Type 'B' is not assignable to type 'A'.
Property 'a' is missing in type 'B'.
tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(23,1): error TS2322: Type 'A | B' is not assignable to type '(A & B) | (C & D)'.
Type 'A' is not assignable to type '(A & B) | (C & D)'.
Type 'A' is not assignable to type 'C & D'.
Type 'A' is not assignable to type 'C'.
tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(25,1): error TS2322: Type 'C | D' is not assignable to type '(A & B) | (C & D)'.
Type 'C' is not assignable to type '(A & B) | (C & D)'.
Type 'C' is not assignable to type 'C & D'.
Type 'C' is not assignable to type 'D'.
tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(26,1): error TS2322: Type '(A & B) | (C & D)' is not assignable to type 'A & B'.
Type 'C & D' is not assignable to type 'A & B'.
Type 'C & D' is not assignable to type 'A'.
Type 'D' is not assignable to type 'A'.
tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(27,1): error TS2322: Type '(A & B) | (C & D)' is not assignable to type 'A | B'.
Type 'C & D' is not assignable to type 'A | B'.
Type 'C & D' is not assignable to type 'B'.
Type 'D' is not assignable to type 'B'.
tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(28,1): error TS2322: Type '(A & B) | (C & D)' is not assignable to type 'C & D'.
Type 'A & B' is not assignable to type 'C & D'.
Type 'A & B' is not assignable to type 'C'.
Type 'B' is not assignable to type 'C'.
tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(29,1): error TS2322: Type '(A & B) | (C & D)' is not assignable to type 'C | D'.
Type 'A & B' is not assignable to type 'C | D'.
Type 'A & B' is not assignable to type 'D'.
Type 'B' is not assignable to type 'D'.
tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(31,1): error TS2322: Type 'A & B' is not assignable to type '(A | B) & (C | D)'.
Type 'A & B' is not assignable to type 'C | D'.
Type 'A & B' is not assignable to type 'D'.
Type 'B' is not assignable to type 'D'.
tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(32,1): error TS2322: Type 'A | B' is not assignable to type '(A | B) & (C | D)'.
Type 'A' is not assignable to type '(A | B) & (C | D)'.
Type 'A' is not assignable to type 'C | D'.
Type 'A' is not assignable to type 'D'.
tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(33,1): error TS2322: Type 'C & D' is not assignable to type '(A | B) & (C | D)'.
Type 'C & D' is not assignable to type 'A | B'.
Type 'C & D' is not assignable to type 'B'.
Type 'D' is not assignable to type 'B'.
tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(34,1): error TS2322: Type 'C | D' is not assignable to type '(A | B) & (C | D)'.
Type 'C' is not assignable to type '(A | B) & (C | D)'.
Type 'C' is not assignable to type 'A | B'.
Type 'C' is not assignable to type 'B'.
tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(35,1): error TS2322: Type '(A | B) & (C | D)' is not assignable to type 'A & B'.
Type '(A | B) & (C | D)' is not assignable to type 'A'.
Type 'C | D' is not assignable to type 'A'.
Type 'C' is not assignable to type 'A'.
tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts(37,1): error TS2322: Type '(A | B) & (C | D)' is not assignable to type 'C & D'.
Type '(A | B) & (C | D)' is not assignable to type 'C'.
Type 'C | D' is not assignable to type 'C'.
Type 'D' is not assignable to type 'C'.
==== tests/cases/conformance/types/intersection/intersectionAndUnionTypes.ts (14 errors) ====
interface A { a: string }
interface B { b: string }
interface C { c: string }
interface D { d: string }
var a: A;
var b: B;
var c: C;
var d: D;
var anb: A & B;
var aob: A | B;
var cnd: C & D;
var cod: C | D;
var x: A & B | C & D;
var y: (A | B) & (C | D);
a = anb; // Ok
b = anb; // Ok
anb = a;
~~~
!!! error TS2322: Type 'A' is not assignable to type 'A & B'.
!!! error TS2322: Type 'A' is not assignable to type 'B'.
anb = b;
~~~
!!! error TS2322: Type 'B' is not assignable to type 'A & B'.
!!! error TS2322: Type 'B' is not assignable to type 'A'.
!!! error TS2322: Property 'a' is missing in type 'B'.
x = anb; // Ok
x = aob;
~
!!! error TS2322: Type 'A | B' is not assignable to type '(A & B) | (C & D)'.
!!! error TS2322: Type 'A' is not assignable to type '(A & B) | (C & D)'.
!!! error TS2322: Type 'A' is not assignable to type 'C & D'.
!!! error TS2322: Type 'A' is not assignable to type 'C'.
x = cnd; // Ok
x = cod;
~
!!! error TS2322: Type 'C | D' is not assignable to type '(A & B) | (C & D)'.
!!! error TS2322: Type 'C' is not assignable to type '(A & B) | (C & D)'.
!!! error TS2322: Type 'C' is not assignable to type 'C & D'.
!!! error TS2322: Type 'C' is not assignable to type 'D'.
anb = x;
~~~
!!! error TS2322: Type '(A & B) | (C & D)' is not assignable to type 'A & B'.
!!! error TS2322: Type 'C & D' is not assignable to type 'A & B'.
!!! error TS2322: Type 'C & D' is not assignable to type 'A'.
!!! error TS2322: Type 'D' is not assignable to type 'A'.
aob = x;
~~~
!!! error TS2322: Type '(A & B) | (C & D)' is not assignable to type 'A | B'.
!!! error TS2322: Type 'C & D' is not assignable to type 'A | B'.
!!! error TS2322: Type 'C & D' is not assignable to type 'B'.
!!! error TS2322: Type 'D' is not assignable to type 'B'.
cnd = x;
~~~
!!! error TS2322: Type '(A & B) | (C & D)' is not assignable to type 'C & D'.
!!! error TS2322: Type 'A & B' is not assignable to type 'C & D'.
!!! error TS2322: Type 'A & B' is not assignable to type 'C'.
!!! error TS2322: Type 'B' is not assignable to type 'C'.
cod = x;
~~~
!!! error TS2322: Type '(A & B) | (C & D)' is not assignable to type 'C | D'.
!!! error TS2322: Type 'A & B' is not assignable to type 'C | D'.
!!! error TS2322: Type 'A & B' is not assignable to type 'D'.
!!! error TS2322: Type 'B' is not assignable to type 'D'.
y = anb;
~
!!! error TS2322: Type 'A & B' is not assignable to type '(A | B) & (C | D)'.
!!! error TS2322: Type 'A & B' is not assignable to type 'C | D'.
!!! error TS2322: Type 'A & B' is not assignable to type 'D'.
!!! error TS2322: Type 'B' is not assignable to type 'D'.
y = aob;
~
!!! error TS2322: Type 'A | B' is not assignable to type '(A | B) & (C | D)'.
!!! error TS2322: Type 'A' is not assignable to type '(A | B) & (C | D)'.
!!! error TS2322: Type 'A' is not assignable to type 'C | D'.
!!! error TS2322: Type 'A' is not assignable to type 'D'.
y = cnd;
~
!!! error TS2322: Type 'C & D' is not assignable to type '(A | B) & (C | D)'.
!!! error TS2322: Type 'C & D' is not assignable to type 'A | B'.
!!! error TS2322: Type 'C & D' is not assignable to type 'B'.
!!! error TS2322: Type 'D' is not assignable to type 'B'.
y = cod;
~
!!! error TS2322: Type 'C | D' is not assignable to type '(A | B) & (C | D)'.
!!! error TS2322: Type 'C' is not assignable to type '(A | B) & (C | D)'.
!!! error TS2322: Type 'C' is not assignable to type 'A | B'.
!!! error TS2322: Type 'C' is not assignable to type 'B'.
anb = y;
~~~
!!! error TS2322: Type '(A | B) & (C | D)' is not assignable to type 'A & B'.
!!! error TS2322: Type '(A | B) & (C | D)' is not assignable to type 'A'.
!!! error TS2322: Type 'C | D' is not assignable to type 'A'.
!!! error TS2322: Type 'C' is not assignable to type 'A'.
aob = y; // Ok
cnd = y;
~~~
!!! error TS2322: Type '(A | B) & (C | D)' is not assignable to type 'C & D'.
!!! error TS2322: Type '(A | B) & (C | D)' is not assignable to type 'C'.
!!! error TS2322: Type 'C | D' is not assignable to type 'C'.
!!! error TS2322: Type 'D' is not assignable to type 'C'.
cod = y; // Ok

View file

@ -0,0 +1,72 @@
//// [intersectionAndUnionTypes.ts]
interface A { a: string }
interface B { b: string }
interface C { c: string }
interface D { d: string }
var a: A;
var b: B;
var c: C;
var d: D;
var anb: A & B;
var aob: A | B;
var cnd: C & D;
var cod: C | D;
var x: A & B | C & D;
var y: (A | B) & (C | D);
a = anb; // Ok
b = anb; // Ok
anb = a;
anb = b;
x = anb; // Ok
x = aob;
x = cnd; // Ok
x = cod;
anb = x;
aob = x;
cnd = x;
cod = x;
y = anb;
y = aob;
y = cnd;
y = cod;
anb = y;
aob = y; // Ok
cnd = y;
cod = y; // Ok
//// [intersectionAndUnionTypes.js]
var a;
var b;
var c;
var d;
var anb;
var aob;
var cnd;
var cod;
var x;
var y;
a = anb; // Ok
b = anb; // Ok
anb = a;
anb = b;
x = anb; // Ok
x = aob;
x = cnd; // Ok
x = cod;
anb = x;
aob = x;
cnd = x;
cod = x;
y = anb;
y = aob;
y = cnd;
y = cod;
anb = y;
aob = y; // Ok
cnd = y;
cod = y; // Ok

View file

@ -0,0 +1,45 @@
tests/cases/conformance/types/intersection/intersectionTypeAssignment.ts(8,1): error TS2322: Type '{ a: string; }' is not assignable to type '{ a: string; b: string; }'.
Property 'b' is missing in type '{ a: string; }'.
tests/cases/conformance/types/intersection/intersectionTypeAssignment.ts(9,1): error TS2322: Type '{ a: string; }' is not assignable to type '{ a: string; } & { b: string; }'.
Type '{ a: string; }' is not assignable to type '{ b: string; }'.
Property 'b' is missing in type '{ a: string; }'.
tests/cases/conformance/types/intersection/intersectionTypeAssignment.ts(13,1): error TS2322: Type '{ b: string; }' is not assignable to type '{ a: string; b: string; }'.
Property 'a' is missing in type '{ b: string; }'.
tests/cases/conformance/types/intersection/intersectionTypeAssignment.ts(14,1): error TS2322: Type '{ b: string; }' is not assignable to type '{ a: string; } & { b: string; }'.
Type '{ b: string; }' is not assignable to type '{ a: string; }'.
Property 'a' is missing in type '{ b: string; }'.
==== tests/cases/conformance/types/intersection/intersectionTypeAssignment.ts (4 errors) ====
var a: { a: string };
var b: { b: string };
var x: { a: string, b: string };
var y: { a: string } & { b: string };
a = x;
a = y;
x = a; // Error
~
!!! error TS2322: Type '{ a: string; }' is not assignable to type '{ a: string; b: string; }'.
!!! error TS2322: Property 'b' is missing in type '{ a: string; }'.
y = a; // Error
~
!!! error TS2322: Type '{ a: string; }' is not assignable to type '{ a: string; } & { b: string; }'.
!!! error TS2322: Type '{ a: string; }' is not assignable to type '{ b: string; }'.
!!! error TS2322: Property 'b' is missing in type '{ a: string; }'.
b = x;
b = y;
x = b; // Error
~
!!! error TS2322: Type '{ b: string; }' is not assignable to type '{ a: string; b: string; }'.
!!! error TS2322: Property 'a' is missing in type '{ b: string; }'.
y = b; // Error
~
!!! error TS2322: Type '{ b: string; }' is not assignable to type '{ a: string; } & { b: string; }'.
!!! error TS2322: Type '{ b: string; }' is not assignable to type '{ a: string; }'.
!!! error TS2322: Property 'a' is missing in type '{ b: string; }'.
x = y;
y = x;

View file

@ -0,0 +1,35 @@
//// [intersectionTypeAssignment.ts]
var a: { a: string };
var b: { b: string };
var x: { a: string, b: string };
var y: { a: string } & { b: string };
a = x;
a = y;
x = a; // Error
y = a; // Error
b = x;
b = y;
x = b; // Error
y = b; // Error
x = y;
y = x;
//// [intersectionTypeAssignment.js]
var a;
var b;
var x;
var y;
a = x;
a = y;
x = a; // Error
y = a; // Error
b = x;
b = y;
x = b; // Error
y = b; // Error
x = y;
y = x;

View file

@ -0,0 +1,31 @@
//// [intersectionTypeEquivalence.ts]
interface A { a: string }
interface B { b: string }
interface C { c: string }
// A & B is equivalent to B & A.
var y: A & B;
var y : B & A;
// AB & C is equivalent to A & BC, where AB is A & B and BC is B & C.
var z : A & B & C;
var z : (A & B) & C;
var z : A & (B & C);
var ab : A & B;
var bc : B & C;
var z1: typeof ab & C;
var z1: A & typeof bc;
//// [intersectionTypeEquivalence.js]
// A & B is equivalent to B & A.
var y;
var y;
// AB & C is equivalent to A & BC, where AB is A & B and BC is B & C.
var z;
var z;
var z;
var ab;
var bc;
var z1;
var z1;

View file

@ -0,0 +1,63 @@
=== tests/cases/conformance/types/intersection/intersectionTypeEquivalence.ts ===
interface A { a: string }
>A : Symbol(A, Decl(intersectionTypeEquivalence.ts, 0, 0))
>a : Symbol(a, Decl(intersectionTypeEquivalence.ts, 0, 13))
interface B { b: string }
>B : Symbol(B, Decl(intersectionTypeEquivalence.ts, 0, 25))
>b : Symbol(b, Decl(intersectionTypeEquivalence.ts, 1, 13))
interface C { c: string }
>C : Symbol(C, Decl(intersectionTypeEquivalence.ts, 1, 25))
>c : Symbol(c, Decl(intersectionTypeEquivalence.ts, 2, 13))
// A & B is equivalent to B & A.
var y: A & B;
>y : Symbol(y, Decl(intersectionTypeEquivalence.ts, 5, 3), Decl(intersectionTypeEquivalence.ts, 6, 3))
>A : Symbol(A, Decl(intersectionTypeEquivalence.ts, 0, 0))
>B : Symbol(B, Decl(intersectionTypeEquivalence.ts, 0, 25))
var y : B & A;
>y : Symbol(y, Decl(intersectionTypeEquivalence.ts, 5, 3), Decl(intersectionTypeEquivalence.ts, 6, 3))
>B : Symbol(B, Decl(intersectionTypeEquivalence.ts, 0, 25))
>A : Symbol(A, Decl(intersectionTypeEquivalence.ts, 0, 0))
// AB & C is equivalent to A & BC, where AB is A & B and BC is B & C.
var z : A & B & C;
>z : Symbol(z, Decl(intersectionTypeEquivalence.ts, 9, 3), Decl(intersectionTypeEquivalence.ts, 10, 3), Decl(intersectionTypeEquivalence.ts, 11, 3))
>A : Symbol(A, Decl(intersectionTypeEquivalence.ts, 0, 0))
>B : Symbol(B, Decl(intersectionTypeEquivalence.ts, 0, 25))
>C : Symbol(C, Decl(intersectionTypeEquivalence.ts, 1, 25))
var z : (A & B) & C;
>z : Symbol(z, Decl(intersectionTypeEquivalence.ts, 9, 3), Decl(intersectionTypeEquivalence.ts, 10, 3), Decl(intersectionTypeEquivalence.ts, 11, 3))
>A : Symbol(A, Decl(intersectionTypeEquivalence.ts, 0, 0))
>B : Symbol(B, Decl(intersectionTypeEquivalence.ts, 0, 25))
>C : Symbol(C, Decl(intersectionTypeEquivalence.ts, 1, 25))
var z : A & (B & C);
>z : Symbol(z, Decl(intersectionTypeEquivalence.ts, 9, 3), Decl(intersectionTypeEquivalence.ts, 10, 3), Decl(intersectionTypeEquivalence.ts, 11, 3))
>A : Symbol(A, Decl(intersectionTypeEquivalence.ts, 0, 0))
>B : Symbol(B, Decl(intersectionTypeEquivalence.ts, 0, 25))
>C : Symbol(C, Decl(intersectionTypeEquivalence.ts, 1, 25))
var ab : A & B;
>ab : Symbol(ab, Decl(intersectionTypeEquivalence.ts, 12, 3))
>A : Symbol(A, Decl(intersectionTypeEquivalence.ts, 0, 0))
>B : Symbol(B, Decl(intersectionTypeEquivalence.ts, 0, 25))
var bc : B & C;
>bc : Symbol(bc, Decl(intersectionTypeEquivalence.ts, 13, 3))
>B : Symbol(B, Decl(intersectionTypeEquivalence.ts, 0, 25))
>C : Symbol(C, Decl(intersectionTypeEquivalence.ts, 1, 25))
var z1: typeof ab & C;
>z1 : Symbol(z1, Decl(intersectionTypeEquivalence.ts, 14, 3), Decl(intersectionTypeEquivalence.ts, 15, 3))
>ab : Symbol(ab, Decl(intersectionTypeEquivalence.ts, 12, 3))
>C : Symbol(C, Decl(intersectionTypeEquivalence.ts, 1, 25))
var z1: A & typeof bc;
>z1 : Symbol(z1, Decl(intersectionTypeEquivalence.ts, 14, 3), Decl(intersectionTypeEquivalence.ts, 15, 3))
>A : Symbol(A, Decl(intersectionTypeEquivalence.ts, 0, 0))
>bc : Symbol(bc, Decl(intersectionTypeEquivalence.ts, 13, 3))

View file

@ -0,0 +1,63 @@
=== tests/cases/conformance/types/intersection/intersectionTypeEquivalence.ts ===
interface A { a: string }
>A : A
>a : string
interface B { b: string }
>B : B
>b : string
interface C { c: string }
>C : C
>c : string
// A & B is equivalent to B & A.
var y: A & B;
>y : A & B
>A : A
>B : B
var y : B & A;
>y : A & B
>B : B
>A : A
// AB & C is equivalent to A & BC, where AB is A & B and BC is B & C.
var z : A & B & C;
>z : A & B & C
>A : A
>B : B
>C : C
var z : (A & B) & C;
>z : A & B & C
>A : A
>B : B
>C : C
var z : A & (B & C);
>z : A & B & C
>A : A
>B : B
>C : C
var ab : A & B;
>ab : A & B
>A : A
>B : B
var bc : B & C;
>bc : B & C
>B : B
>C : C
var z1: typeof ab & C;
>z1 : A & B & C
>ab : A & B
>C : C
var z1: A & typeof bc;
>z1 : A & B & C
>A : A
>bc : B & C

View file

@ -0,0 +1,41 @@
tests/cases/conformance/types/intersection/intersectionTypeInference.ts(5,5): error TS2322: Type 'T' is not assignable to type 'T & U'.
Type 'T' is not assignable to type 'U'.
tests/cases/conformance/types/intersection/intersectionTypeInference.ts(6,5): error TS2322: Type 'U' is not assignable to type 'T & U'.
Type 'U' is not assignable to type 'T'.
==== tests/cases/conformance/types/intersection/intersectionTypeInference.ts (2 errors) ====
function extend<T, U>(obj1: T, obj2: U): T & U {
var result: T & U;
obj1 = result;
obj2 = result;
result = obj1; // Error
~~~~~~
!!! error TS2322: Type 'T' is not assignable to type 'T & U'.
!!! error TS2322: Type 'T' is not assignable to type 'U'.
result = obj2; // Error
~~~~~~
!!! error TS2322: Type 'U' is not assignable to type 'T & U'.
!!! error TS2322: Type 'U' is not assignable to type 'T'.
return result;
}
var x = extend({ a: "hello" }, { b: 42 });
var s = x.a;
var n = x.b;
interface A<T> {
a: T;
}
interface B<U> {
b: U;
}
function foo<T, U>(obj: A<T> & B<U>): T | U {
return undefined;
}
var z = foo({ a: "hello", b: 42 });
var z: string | number;

View file

@ -0,0 +1,47 @@
//// [intersectionTypeInference.ts]
function extend<T, U>(obj1: T, obj2: U): T & U {
var result: T & U;
obj1 = result;
obj2 = result;
result = obj1; // Error
result = obj2; // Error
return result;
}
var x = extend({ a: "hello" }, { b: 42 });
var s = x.a;
var n = x.b;
interface A<T> {
a: T;
}
interface B<U> {
b: U;
}
function foo<T, U>(obj: A<T> & B<U>): T | U {
return undefined;
}
var z = foo({ a: "hello", b: 42 });
var z: string | number;
//// [intersectionTypeInference.js]
function extend(obj1, obj2) {
var result;
obj1 = result;
obj2 = result;
result = obj1; // Error
result = obj2; // Error
return result;
}
var x = extend({ a: "hello" }, { b: 42 });
var s = x.a;
var n = x.b;
function foo(obj) {
return undefined;
}
var z = foo({ a: "hello", b: 42 });
var z;

View file

@ -0,0 +1,44 @@
//// [intersectionTypeMembers.ts]
// An intersection type has those members that are present in any of its constituent types,
// with types that are intersections of the respective members in the constituent types
interface A { a: string }
interface B { b: string }
interface C { c: string }
var abc: A & B & C;
abc.a = "hello";
abc.b = "hello";
abc.c = "hello";
interface X { x: A }
interface Y { x: B }
interface Z { x: C }
var xyz: X & Y & Z;
xyz.x.a = "hello";
xyz.x.b = "hello";
xyz.x.c = "hello";
type F1 = (x: string) => string;
type F2 = (x: number) => number;
var f: F1 & F2;
var s = f("hello");
var n = f(42);
//// [intersectionTypeMembers.js]
// An intersection type has those members that are present in any of its constituent types,
// with types that are intersections of the respective members in the constituent types
var abc;
abc.a = "hello";
abc.b = "hello";
abc.c = "hello";
var xyz;
xyz.x.a = "hello";
xyz.x.b = "hello";
xyz.x.c = "hello";
var f;
var s = f("hello");
var n = f(42);

View file

@ -0,0 +1,100 @@
=== tests/cases/conformance/types/intersection/intersectionTypeMembers.ts ===
// An intersection type has those members that are present in any of its constituent types,
// with types that are intersections of the respective members in the constituent types
interface A { a: string }
>A : Symbol(A, Decl(intersectionTypeMembers.ts, 0, 0))
>a : Symbol(a, Decl(intersectionTypeMembers.ts, 3, 13))
interface B { b: string }
>B : Symbol(B, Decl(intersectionTypeMembers.ts, 3, 25))
>b : Symbol(b, Decl(intersectionTypeMembers.ts, 4, 13))
interface C { c: string }
>C : Symbol(C, Decl(intersectionTypeMembers.ts, 4, 25))
>c : Symbol(c, Decl(intersectionTypeMembers.ts, 5, 13))
var abc: A & B & C;
>abc : Symbol(abc, Decl(intersectionTypeMembers.ts, 7, 3))
>A : Symbol(A, Decl(intersectionTypeMembers.ts, 0, 0))
>B : Symbol(B, Decl(intersectionTypeMembers.ts, 3, 25))
>C : Symbol(C, Decl(intersectionTypeMembers.ts, 4, 25))
abc.a = "hello";
>abc.a : Symbol(A.a, Decl(intersectionTypeMembers.ts, 3, 13))
>abc : Symbol(abc, Decl(intersectionTypeMembers.ts, 7, 3))
>a : Symbol(A.a, Decl(intersectionTypeMembers.ts, 3, 13))
abc.b = "hello";
>abc.b : Symbol(B.b, Decl(intersectionTypeMembers.ts, 4, 13))
>abc : Symbol(abc, Decl(intersectionTypeMembers.ts, 7, 3))
>b : Symbol(B.b, Decl(intersectionTypeMembers.ts, 4, 13))
abc.c = "hello";
>abc.c : Symbol(C.c, Decl(intersectionTypeMembers.ts, 5, 13))
>abc : Symbol(abc, Decl(intersectionTypeMembers.ts, 7, 3))
>c : Symbol(C.c, Decl(intersectionTypeMembers.ts, 5, 13))
interface X { x: A }
>X : Symbol(X, Decl(intersectionTypeMembers.ts, 10, 16))
>x : Symbol(x, Decl(intersectionTypeMembers.ts, 12, 13))
>A : Symbol(A, Decl(intersectionTypeMembers.ts, 0, 0))
interface Y { x: B }
>Y : Symbol(Y, Decl(intersectionTypeMembers.ts, 12, 20))
>x : Symbol(x, Decl(intersectionTypeMembers.ts, 13, 13))
>B : Symbol(B, Decl(intersectionTypeMembers.ts, 3, 25))
interface Z { x: C }
>Z : Symbol(Z, Decl(intersectionTypeMembers.ts, 13, 20))
>x : Symbol(x, Decl(intersectionTypeMembers.ts, 14, 13))
>C : Symbol(C, Decl(intersectionTypeMembers.ts, 4, 25))
var xyz: X & Y & Z;
>xyz : Symbol(xyz, Decl(intersectionTypeMembers.ts, 16, 3))
>X : Symbol(X, Decl(intersectionTypeMembers.ts, 10, 16))
>Y : Symbol(Y, Decl(intersectionTypeMembers.ts, 12, 20))
>Z : Symbol(Z, Decl(intersectionTypeMembers.ts, 13, 20))
xyz.x.a = "hello";
>xyz.x.a : Symbol(A.a, Decl(intersectionTypeMembers.ts, 3, 13))
>xyz.x : Symbol(x, Decl(intersectionTypeMembers.ts, 12, 13), Decl(intersectionTypeMembers.ts, 13, 13), Decl(intersectionTypeMembers.ts, 14, 13))
>xyz : Symbol(xyz, Decl(intersectionTypeMembers.ts, 16, 3))
>x : Symbol(x, Decl(intersectionTypeMembers.ts, 12, 13), Decl(intersectionTypeMembers.ts, 13, 13), Decl(intersectionTypeMembers.ts, 14, 13))
>a : Symbol(A.a, Decl(intersectionTypeMembers.ts, 3, 13))
xyz.x.b = "hello";
>xyz.x.b : Symbol(B.b, Decl(intersectionTypeMembers.ts, 4, 13))
>xyz.x : Symbol(x, Decl(intersectionTypeMembers.ts, 12, 13), Decl(intersectionTypeMembers.ts, 13, 13), Decl(intersectionTypeMembers.ts, 14, 13))
>xyz : Symbol(xyz, Decl(intersectionTypeMembers.ts, 16, 3))
>x : Symbol(x, Decl(intersectionTypeMembers.ts, 12, 13), Decl(intersectionTypeMembers.ts, 13, 13), Decl(intersectionTypeMembers.ts, 14, 13))
>b : Symbol(B.b, Decl(intersectionTypeMembers.ts, 4, 13))
xyz.x.c = "hello";
>xyz.x.c : Symbol(C.c, Decl(intersectionTypeMembers.ts, 5, 13))
>xyz.x : Symbol(x, Decl(intersectionTypeMembers.ts, 12, 13), Decl(intersectionTypeMembers.ts, 13, 13), Decl(intersectionTypeMembers.ts, 14, 13))
>xyz : Symbol(xyz, Decl(intersectionTypeMembers.ts, 16, 3))
>x : Symbol(x, Decl(intersectionTypeMembers.ts, 12, 13), Decl(intersectionTypeMembers.ts, 13, 13), Decl(intersectionTypeMembers.ts, 14, 13))
>c : Symbol(C.c, Decl(intersectionTypeMembers.ts, 5, 13))
type F1 = (x: string) => string;
>F1 : Symbol(F1, Decl(intersectionTypeMembers.ts, 19, 18))
>x : Symbol(x, Decl(intersectionTypeMembers.ts, 21, 11))
type F2 = (x: number) => number;
>F2 : Symbol(F2, Decl(intersectionTypeMembers.ts, 21, 32))
>x : Symbol(x, Decl(intersectionTypeMembers.ts, 22, 11))
var f: F1 & F2;
>f : Symbol(f, Decl(intersectionTypeMembers.ts, 24, 3))
>F1 : Symbol(F1, Decl(intersectionTypeMembers.ts, 19, 18))
>F2 : Symbol(F2, Decl(intersectionTypeMembers.ts, 21, 32))
var s = f("hello");
>s : Symbol(s, Decl(intersectionTypeMembers.ts, 25, 3))
>f : Symbol(f, Decl(intersectionTypeMembers.ts, 24, 3))
var n = f(42);
>n : Symbol(n, Decl(intersectionTypeMembers.ts, 26, 3))
>f : Symbol(f, Decl(intersectionTypeMembers.ts, 24, 3))

View file

@ -0,0 +1,116 @@
=== tests/cases/conformance/types/intersection/intersectionTypeMembers.ts ===
// An intersection type has those members that are present in any of its constituent types,
// with types that are intersections of the respective members in the constituent types
interface A { a: string }
>A : A
>a : string
interface B { b: string }
>B : B
>b : string
interface C { c: string }
>C : C
>c : string
var abc: A & B & C;
>abc : A & B & C
>A : A
>B : B
>C : C
abc.a = "hello";
>abc.a = "hello" : string
>abc.a : string
>abc : A & B & C
>a : string
>"hello" : string
abc.b = "hello";
>abc.b = "hello" : string
>abc.b : string
>abc : A & B & C
>b : string
>"hello" : string
abc.c = "hello";
>abc.c = "hello" : string
>abc.c : string
>abc : A & B & C
>c : string
>"hello" : string
interface X { x: A }
>X : X
>x : A
>A : A
interface Y { x: B }
>Y : Y
>x : B
>B : B
interface Z { x: C }
>Z : Z
>x : C
>C : C
var xyz: X & Y & Z;
>xyz : X & Y & Z
>X : X
>Y : Y
>Z : Z
xyz.x.a = "hello";
>xyz.x.a = "hello" : string
>xyz.x.a : string
>xyz.x : A & B & C
>xyz : X & Y & Z
>x : A & B & C
>a : string
>"hello" : string
xyz.x.b = "hello";
>xyz.x.b = "hello" : string
>xyz.x.b : string
>xyz.x : A & B & C
>xyz : X & Y & Z
>x : A & B & C
>b : string
>"hello" : string
xyz.x.c = "hello";
>xyz.x.c = "hello" : string
>xyz.x.c : string
>xyz.x : A & B & C
>xyz : X & Y & Z
>x : A & B & C
>c : string
>"hello" : string
type F1 = (x: string) => string;
>F1 : (x: string) => string
>x : string
type F2 = (x: number) => number;
>F2 : (x: number) => number
>x : number
var f: F1 & F2;
>f : ((x: string) => string) & ((x: number) => number)
>F1 : (x: string) => string
>F2 : (x: number) => number
var s = f("hello");
>s : string
>f("hello") : string
>f : ((x: string) => string) & ((x: number) => number)
>"hello" : string
var n = f(42);
>n : number
>f(42) : number
>f : ((x: string) => string) & ((x: number) => number)
>42 : number

View file

@ -0,0 +1,26 @@
//// [intersectionTypeOverloading.ts]
// Check that order is preserved in intersection types for purposes of
// overload resolution
type F = (s: string) => string;
type G = (x: any) => any;
var fg: F & G;
var gf: G & F;
var x = fg("abc");
var x: string;
var y = gf("abc");
var y: any;
//// [intersectionTypeOverloading.js]
// Check that order is preserved in intersection types for purposes of
// overload resolution
var fg;
var gf;
var x = fg("abc");
var x;
var y = gf("abc");
var y;

View file

@ -0,0 +1,36 @@
=== tests/cases/conformance/types/intersection/intersectionTypeOverloading.ts ===
// Check that order is preserved in intersection types for purposes of
// overload resolution
type F = (s: string) => string;
>F : Symbol(F, Decl(intersectionTypeOverloading.ts, 0, 0))
>s : Symbol(s, Decl(intersectionTypeOverloading.ts, 3, 10))
type G = (x: any) => any;
>G : Symbol(G, Decl(intersectionTypeOverloading.ts, 3, 31))
>x : Symbol(x, Decl(intersectionTypeOverloading.ts, 4, 10))
var fg: F & G;
>fg : Symbol(fg, Decl(intersectionTypeOverloading.ts, 6, 3))
>F : Symbol(F, Decl(intersectionTypeOverloading.ts, 0, 0))
>G : Symbol(G, Decl(intersectionTypeOverloading.ts, 3, 31))
var gf: G & F;
>gf : Symbol(gf, Decl(intersectionTypeOverloading.ts, 7, 3))
>G : Symbol(G, Decl(intersectionTypeOverloading.ts, 3, 31))
>F : Symbol(F, Decl(intersectionTypeOverloading.ts, 0, 0))
var x = fg("abc");
>x : Symbol(x, Decl(intersectionTypeOverloading.ts, 9, 3), Decl(intersectionTypeOverloading.ts, 10, 3))
>fg : Symbol(fg, Decl(intersectionTypeOverloading.ts, 6, 3))
var x: string;
>x : Symbol(x, Decl(intersectionTypeOverloading.ts, 9, 3), Decl(intersectionTypeOverloading.ts, 10, 3))
var y = gf("abc");
>y : Symbol(y, Decl(intersectionTypeOverloading.ts, 12, 3), Decl(intersectionTypeOverloading.ts, 13, 3))
>gf : Symbol(gf, Decl(intersectionTypeOverloading.ts, 7, 3))
var y: any;
>y : Symbol(y, Decl(intersectionTypeOverloading.ts, 12, 3), Decl(intersectionTypeOverloading.ts, 13, 3))

View file

@ -0,0 +1,40 @@
=== tests/cases/conformance/types/intersection/intersectionTypeOverloading.ts ===
// Check that order is preserved in intersection types for purposes of
// overload resolution
type F = (s: string) => string;
>F : (s: string) => string
>s : string
type G = (x: any) => any;
>G : (x: any) => any
>x : any
var fg: F & G;
>fg : ((s: string) => string) & ((x: any) => any)
>F : (s: string) => string
>G : (x: any) => any
var gf: G & F;
>gf : ((x: any) => any) & ((s: string) => string)
>G : (x: any) => any
>F : (s: string) => string
var x = fg("abc");
>x : string
>fg("abc") : string
>fg : ((s: string) => string) & ((x: any) => any)
>"abc" : string
var x: string;
>x : string
var y = gf("abc");
>y : any
>gf("abc") : any
>gf : ((x: any) => any) & ((s: string) => string)
>"abc" : string
var y: any;
>y : any

View file

@ -0,0 +1,32 @@
tests/cases/conformance/types/intersection/recursiveIntersectionTypes.ts(19,1): error TS2322: Type 'Entity & { next: Entity & any; }' is not assignable to type 'Product & { next: Product & any; }'.
Type 'Entity & { next: Entity & any; }' is not assignable to type 'Product'.
Type '{ next: Entity & any; }' is not assignable to type 'Product'.
Property 'price' is missing in type '{ next: Entity & any; }'.
==== tests/cases/conformance/types/intersection/recursiveIntersectionTypes.ts (1 errors) ====
type LinkedList<T> = T & { next: LinkedList<T> };
interface Entity {
name: string;
}
interface Product extends Entity {
price: number;
}
var entityList: LinkedList<Entity>;
var s = entityList.name;
var s = entityList.next.name;
var s = entityList.next.next.name;
var s = entityList.next.next.next.name;
var productList: LinkedList<Product>;
entityList = productList;
productList = entityList; // Error
~~~~~~~~~~~
!!! error TS2322: Type 'Entity & { next: Entity & any; }' is not assignable to type 'Product & { next: Product & any; }'.
!!! error TS2322: Type 'Entity & { next: Entity & any; }' is not assignable to type 'Product'.
!!! error TS2322: Type '{ next: Entity & any; }' is not assignable to type 'Product'.
!!! error TS2322: Property 'price' is missing in type '{ next: Entity & any; }'.

View file

@ -0,0 +1,31 @@
//// [recursiveIntersectionTypes.ts]
type LinkedList<T> = T & { next: LinkedList<T> };
interface Entity {
name: string;
}
interface Product extends Entity {
price: number;
}
var entityList: LinkedList<Entity>;
var s = entityList.name;
var s = entityList.next.name;
var s = entityList.next.next.name;
var s = entityList.next.next.next.name;
var productList: LinkedList<Product>;
entityList = productList;
productList = entityList; // Error
//// [recursiveIntersectionTypes.js]
var entityList;
var s = entityList.name;
var s = entityList.next.name;
var s = entityList.next.next.name;
var s = entityList.next.next.next.name;
var productList;
entityList = productList;
productList = entityList; // Error

View file

@ -33,9 +33,9 @@ function f<T extends Cat | Dog>(a: T) {
>T : Symbol(T, Decl(typeParameterExtendingUnion1.ts, 8, 11))
a.run();
>a.run : Symbol(run, Decl(typeParameterExtendingUnion1.ts, 0, 14), Decl(typeParameterExtendingUnion1.ts, 0, 14))
>a.run : Symbol(Animal.run, Decl(typeParameterExtendingUnion1.ts, 0, 14))
>a : Symbol(a, Decl(typeParameterExtendingUnion1.ts, 8, 32))
>run : Symbol(run, Decl(typeParameterExtendingUnion1.ts, 0, 14), Decl(typeParameterExtendingUnion1.ts, 0, 14))
>run : Symbol(Animal.run, Decl(typeParameterExtendingUnion1.ts, 0, 14))
run(a);
>run : Symbol(run, Decl(typeParameterExtendingUnion1.ts, 2, 33))

View file

@ -20,9 +20,9 @@ function run(a: Cat | Dog) {
>Dog : Symbol(Dog, Decl(typeParameterExtendingUnion2.ts, 1, 33))
a.run();
>a.run : Symbol(run, Decl(typeParameterExtendingUnion2.ts, 0, 14), Decl(typeParameterExtendingUnion2.ts, 0, 14))
>a.run : Symbol(Animal.run, Decl(typeParameterExtendingUnion2.ts, 0, 14))
>a : Symbol(a, Decl(typeParameterExtendingUnion2.ts, 4, 13))
>run : Symbol(run, Decl(typeParameterExtendingUnion2.ts, 0, 14), Decl(typeParameterExtendingUnion2.ts, 0, 14))
>run : Symbol(Animal.run, Decl(typeParameterExtendingUnion2.ts, 0, 14))
}
function f<T extends Cat | Dog>(a: T) {
@ -34,9 +34,9 @@ function f<T extends Cat | Dog>(a: T) {
>T : Symbol(T, Decl(typeParameterExtendingUnion2.ts, 8, 11))
a.run();
>a.run : Symbol(run, Decl(typeParameterExtendingUnion2.ts, 0, 14), Decl(typeParameterExtendingUnion2.ts, 0, 14))
>a.run : Symbol(Animal.run, Decl(typeParameterExtendingUnion2.ts, 0, 14))
>a : Symbol(a, Decl(typeParameterExtendingUnion2.ts, 8, 32))
>run : Symbol(run, Decl(typeParameterExtendingUnion2.ts, 0, 14), Decl(typeParameterExtendingUnion2.ts, 0, 14))
>run : Symbol(Animal.run, Decl(typeParameterExtendingUnion2.ts, 0, 14))
run(a);
>run : Symbol(run, Decl(typeParameterExtendingUnion2.ts, 2, 33))

View file

@ -0,0 +1,5 @@
var x: { a: (s: string) => string } & { b: (n: number) => number };
x = {
a: s => s,
b: n => n
};

View file

@ -0,0 +1,38 @@
interface A { a: string }
interface B { b: string }
interface C { c: string }
interface D { d: string }
var a: A;
var b: B;
var c: C;
var d: D;
var anb: A & B;
var aob: A | B;
var cnd: C & D;
var cod: C | D;
var x: A & B | C & D;
var y: (A | B) & (C | D);
a = anb; // Ok
b = anb; // Ok
anb = a;
anb = b;
x = anb; // Ok
x = aob;
x = cnd; // Ok
x = cod;
anb = x;
aob = x;
cnd = x;
cod = x;
y = anb;
y = aob;
y = cnd;
y = cod;
anb = y;
aob = y; // Ok
cnd = y;
cod = y; // Ok

View file

@ -0,0 +1,17 @@
var a: { a: string };
var b: { b: string };
var x: { a: string, b: string };
var y: { a: string } & { b: string };
a = x;
a = y;
x = a; // Error
y = a; // Error
b = x;
b = y;
x = b; // Error
y = b; // Error
x = y;
y = x;

View file

@ -0,0 +1,16 @@
interface A { a: string }
interface B { b: string }
interface C { c: string }
// A & B is equivalent to B & A.
var y: A & B;
var y : B & A;
// AB & C is equivalent to A & BC, where AB is A & B and BC is B & C.
var z : A & B & C;
var z : (A & B) & C;
var z : A & (B & C);
var ab : A & B;
var bc : B & C;
var z1: typeof ab & C;
var z1: A & typeof bc;

View file

@ -0,0 +1,27 @@
function extend<T, U>(obj1: T, obj2: U): T & U {
var result: T & U;
obj1 = result;
obj2 = result;
result = obj1; // Error
result = obj2; // Error
return result;
}
var x = extend({ a: "hello" }, { b: 42 });
var s = x.a;
var n = x.b;
interface A<T> {
a: T;
}
interface B<U> {
b: U;
}
function foo<T, U>(obj: A<T> & B<U>): T | U {
return undefined;
}
var z = foo({ a: "hello", b: 42 });
var z: string | number;

View file

@ -0,0 +1,27 @@
// An intersection type has those members that are present in any of its constituent types,
// with types that are intersections of the respective members in the constituent types
interface A { a: string }
interface B { b: string }
interface C { c: string }
var abc: A & B & C;
abc.a = "hello";
abc.b = "hello";
abc.c = "hello";
interface X { x: A }
interface Y { x: B }
interface Z { x: C }
var xyz: X & Y & Z;
xyz.x.a = "hello";
xyz.x.b = "hello";
xyz.x.c = "hello";
type F1 = (x: string) => string;
type F2 = (x: number) => number;
var f: F1 & F2;
var s = f("hello");
var n = f(42);

View file

@ -0,0 +1,14 @@
// Check that order is preserved in intersection types for purposes of
// overload resolution
type F = (s: string) => string;
type G = (x: any) => any;
var fg: F & G;
var gf: G & F;
var x = fg("abc");
var x: string;
var y = gf("abc");
var y: any;

View file

@ -0,0 +1,19 @@
type LinkedList<T> = T & { next: LinkedList<T> };
interface Entity {
name: string;
}
interface Product extends Entity {
price: number;
}
var entityList: LinkedList<Entity>;
var s = entityList.name;
var s = entityList.next.name;
var s = entityList.next.next.name;
var s = entityList.next.next.next.name;
var productList: LinkedList<Product>;
entityList = productList;
productList = entityList; // Error