@@ -2465,7 +2465,8 @@ namespace ts {
2465
2465
const symbol = type.symbol;
2466
2466
if (symbol) {
2467
2467
// Always use 'typeof T' for type of class, enum, and module objects
2468
- if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) {
2468
+ if (symbol.flags & SymbolFlags.Class && !getBaseTypeVariableOfClass(symbol) ||
2469
+ symbol.flags & (SymbolFlags.Enum | SymbolFlags.ValueModule)) {
2469
2470
writeTypeOfSymbol(type, flags);
2470
2471
}
2471
2472
else if (shouldWriteTypeOfFunctionSymbol()) {
@@ -3639,6 +3640,11 @@ namespace ts {
3639
3640
return links.type;
3640
3641
}
3641
3642
3643
+ function getBaseTypeVariableOfClass(symbol: Symbol) {
3644
+ const baseConstructorType = getBaseConstructorTypeOfClass(getDeclaredTypeOfClassOrInterface(symbol));
3645
+ return baseConstructorType.flags & TypeFlags.TypeVariable ? baseConstructorType : undefined;
3646
+ }
3647
+
3642
3648
function getTypeOfFuncClassEnumModule(symbol: Symbol): Type {
3643
3649
const links = getSymbolLinks(symbol);
3644
3650
if (!links.type) {
@@ -3647,8 +3653,13 @@ namespace ts {
3647
3653
}
3648
3654
else {
3649
3655
const type = createObjectType(ObjectFlags.Anonymous, symbol);
3650
- links.type = strictNullChecks && symbol.flags & SymbolFlags.Optional ?
3651
- includeFalsyTypes(type, TypeFlags.Undefined) : type;
3656
+ if (symbol.flags & SymbolFlags.Class) {
3657
+ const baseTypeVariable = getBaseTypeVariableOfClass(symbol);
3658
+ links.type = baseTypeVariable ? getIntersectionType([type, baseTypeVariable]) : type;
3659
+ }
3660
+ else {
3661
+ links.type = strictNullChecks && symbol.flags & SymbolFlags.Optional ? includeFalsyTypes(type, TypeFlags.Undefined) : type;
3662
+ }
3652
3663
}
3653
3664
}
3654
3665
return links.type;
@@ -3812,8 +3823,26 @@ namespace ts {
3812
3823
return concatenate(getOuterTypeParametersOfClassOrInterface(symbol), getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol));
3813
3824
}
3814
3825
3826
+ // A type is a mixin constructor if it has a single construct signature taking no type parameters and a single
3827
+ // rest parameter of type any[].
3828
+ function isMixinConstructorType(type: Type) {
3829
+ const signatures = getSignaturesOfType(type, SignatureKind.Construct);
3830
+ if (signatures.length === 1) {
3831
+ const s = signatures[0];
3832
+ return !s.typeParameters && s.parameters.length === 1 && s.hasRestParameter && getTypeOfParameter(s.parameters[0]) === anyArrayType;
3833
+ }
3834
+ return false;
3835
+ }
3836
+
3815
3837
function isConstructorType(type: Type): boolean {
3816
- return isValidBaseType(type) && getSignaturesOfType(type, SignatureKind.Construct).length > 0;
3838
+ if (isValidBaseType(type) && getSignaturesOfType(type, SignatureKind.Construct).length > 0) {
3839
+ return true;
3840
+ }
3841
+ if (type.flags & TypeFlags.TypeVariable) {
3842
+ const constraint = getBaseConstraintOfType(<TypeVariable>type);
3843
+ return isValidBaseType(constraint) && isMixinConstructorType(constraint);
3844
+ }
3845
+ return false;
3817
3846
}
3818
3847
3819
3848
function getBaseTypeNodeOfClass(type: InterfaceType): ExpressionWithTypeArguments {
@@ -3892,7 +3921,7 @@ namespace ts {
3892
3921
3893
3922
function resolveBaseTypesOfClass(type: InterfaceType): void {
3894
3923
type.resolvedBaseTypes = type.resolvedBaseTypes || emptyArray;
3895
- const baseConstructorType = <ObjectType> getBaseConstructorTypeOfClass(type);
3924
+ const baseConstructorType = getApparentType( getBaseConstructorTypeOfClass(type) );
3896
3925
if (!(baseConstructorType.flags & (TypeFlags.Object | TypeFlags.Intersection))) {
3897
3926
return;
3898
3927
}
@@ -4542,16 +4571,47 @@ namespace ts {
4542
4571
getUnionType([info1.type, info2.type]), info1.isReadonly || info2.isReadonly);
4543
4572
}
4544
4573
4574
+ function includeMixinType(type: Type, types: Type[], index: number): Type {
4575
+ const mixedTypes: Type[] = [];
4576
+ for (let i = 0; i < types.length; i++) {
4577
+ if (i === index) {
4578
+ mixedTypes.push(type);
4579
+ }
4580
+ else if (isMixinConstructorType(types[i])) {
4581
+ mixedTypes.push(getReturnTypeOfSignature(getSignaturesOfType(types[i], SignatureKind.Construct)[0]));
4582
+ }
4583
+ }
4584
+ return getIntersectionType(mixedTypes);
4585
+ }
4586
+
4545
4587
function resolveIntersectionTypeMembers(type: IntersectionType) {
4546
4588
// The members and properties collections are empty for intersection types. To get all properties of an
4547
4589
// intersection type use getPropertiesOfType (only the language service uses this).
4548
4590
let callSignatures: Signature[] = emptyArray;
4549
4591
let constructSignatures: Signature[] = emptyArray;
4550
- let stringIndexInfo: IndexInfo = undefined;
4551
- let numberIndexInfo: IndexInfo = undefined;
4552
- for (const t of type.types) {
4592
+ let stringIndexInfo: IndexInfo;
4593
+ let numberIndexInfo: IndexInfo;
4594
+ const types = type.types;
4595
+ const mixinCount = countWhere(types, isMixinConstructorType);
4596
+ for (let i = 0; i < types.length; i++) {
4597
+ const t = type.types[i];
4598
+ // When an intersection type contains mixin constructor types, the construct signatures from
4599
+ // those types are discarded and their return types are mixed into the return types of all
4600
+ // other construct signatures in the intersection type. For example, the intersection type
4601
+ // '{ new(...args: any[]) => A } & { new(s: string) => B }' has a single construct signature
4602
+ // 'new(s: string) => A & B'.
4603
+ if (mixinCount === 0 || mixinCount === types.length && i === 0 || !isMixinConstructorType(t)) {
4604
+ let signatures = getSignaturesOfType(t, SignatureKind.Construct);
4605
+ if (signatures.length && mixinCount > 0) {
4606
+ signatures = map(signatures, s => {
4607
+ const clone = cloneSignature(s);
4608
+ clone.resolvedReturnType = includeMixinType(getReturnTypeOfSignature(s), types, i);
4609
+ return clone;
4610
+ });
4611
+ }
4612
+ constructSignatures = concatenate(constructSignatures, signatures);
4613
+ }
4553
4614
callSignatures = concatenate(callSignatures, getSignaturesOfType(t, SignatureKind.Call));
4554
- constructSignatures = concatenate(constructSignatures, getSignaturesOfType(t, SignatureKind.Construct));
4555
4615
stringIndexInfo = intersectIndexInfos(stringIndexInfo, getIndexInfoOfType(t, IndexKind.String));
4556
4616
numberIndexInfo = intersectIndexInfos(numberIndexInfo, getIndexInfoOfType(t, IndexKind.Number));
4557
4617
}
@@ -4593,7 +4653,7 @@ namespace ts {
4593
4653
constructSignatures = getDefaultConstructSignatures(classType);
4594
4654
}
4595
4655
const baseConstructorType = getBaseConstructorTypeOfClass(classType);
4596
- if (baseConstructorType.flags & (TypeFlags.Object | TypeFlags.Intersection)) {
4656
+ if (baseConstructorType.flags & (TypeFlags.Object | TypeFlags.Intersection | TypeFlags.TypeVariable )) {
4597
4657
members = createSymbolTable(getNamedMembers(members));
4598
4658
addInheritedMembers(members, getPropertiesOfType(baseConstructorType));
4599
4659
}
@@ -4890,6 +4950,7 @@ namespace ts {
4890
4950
4891
4951
function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: string): Symbol {
4892
4952
const types = containingType.types;
4953
+ const excludeModifiers = containingType.flags & TypeFlags.Union ? ModifierFlags.Private | ModifierFlags.Protected : 0;
4893
4954
let props: Symbol[];
4894
4955
// Flags we want to propagate to the result if they exist in all source symbols
4895
4956
let commonFlags = (containingType.flags & TypeFlags.Intersection) ? SymbolFlags.Optional : SymbolFlags.None;
@@ -4899,7 +4960,7 @@ namespace ts {
4899
4960
const type = getApparentType(current);
4900
4961
if (type !== unknownType) {
4901
4962
const prop = getPropertyOfType(type, name);
4902
- if (prop && !(getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected) )) {
4963
+ if (prop && !(getDeclarationModifierFlagsFromSymbol(prop) & excludeModifiers )) {
4903
4964
commonFlags &= prop.flags;
4904
4965
if (!props) {
4905
4966
props = [prop];
@@ -6965,9 +7026,12 @@ namespace ts {
6965
7026
result.properties = resolved.properties;
6966
7027
result.callSignatures = emptyArray;
6967
7028
result.constructSignatures = emptyArray;
6968
- type = result;
7029
+ return result;
6969
7030
}
6970
7031
}
7032
+ else if (type.flags & TypeFlags.Intersection) {
7033
+ return getIntersectionType(map((<IntersectionType>type).types, getTypeWithoutSignatures));
7034
+ }
6971
7035
return type;
6972
7036
}
6973
7037
@@ -18390,7 +18454,8 @@ namespace ts {
18390
18454
const baseTypes = getBaseTypes(type);
18391
18455
if (baseTypes.length && produceDiagnostics) {
18392
18456
const baseType = baseTypes[0];
18393
- const staticBaseType = getBaseConstructorTypeOfClass(type);
18457
+ const baseConstructorType = getBaseConstructorTypeOfClass(type);
18458
+ const staticBaseType = getApparentType(baseConstructorType);
18394
18459
checkBaseTypeAccessibility(staticBaseType, baseTypeNode);
18395
18460
checkSourceElement(baseTypeNode.expression);
18396
18461
if (baseTypeNode.typeArguments) {
@@ -18404,6 +18469,9 @@ namespace ts {
18404
18469
checkTypeAssignableTo(typeWithThis, getTypeWithThisArgument(baseType, type.thisType), node.name || node, Diagnostics.Class_0_incorrectly_extends_base_class_1);
18405
18470
checkTypeAssignableTo(staticType, getTypeWithoutSignatures(staticBaseType), node.name || node,
18406
18471
Diagnostics.Class_static_side_0_incorrectly_extends_base_class_static_side_1);
18472
+ if (baseConstructorType.flags & TypeFlags.TypeVariable && !isMixinConstructorType(staticType)) {
18473
+ error(node.name || node, Diagnostics.A_mixin_class_must_have_a_constructor_with_a_single_rest_parameter_of_type_any);
18474
+ }
18407
18475
18408
18476
if (baseType.symbol && baseType.symbol.valueDeclaration &&
18409
18477
!isInAmbientContext(baseType.symbol.valueDeclaration) &&
@@ -18413,7 +18481,7 @@ namespace ts {
18413
18481
}
18414
18482
}
18415
18483
18416
- if (!(staticBaseType.symbol && staticBaseType.symbol.flags & SymbolFlags.Class)) {
18484
+ if (!(staticBaseType.symbol && staticBaseType.symbol.flags & SymbolFlags.Class) && !(baseConstructorType.flags & TypeFlags.TypeVariable) ) {
18417
18485
// When the static base type is a "class-like" constructor function (but not actually a class), we verify
18418
18486
// that all instantiated base constructor signatures return the same type. We can simply compare the type
18419
18487
// references (as opposed to checking the structure of the types) because elsewhere we have already checked
0 commit comments