@@ -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
}
@@ -4547,11 +4576,32 @@ namespace ts {
4547
4576
// intersection type use getPropertiesOfType (only the language service uses this).
4548
4577
let callSignatures: Signature[] = emptyArray;
4549
4578
let constructSignatures: Signature[] = emptyArray;
4550
- let stringIndexInfo: IndexInfo = undefined;
4551
- let numberIndexInfo: IndexInfo = undefined;
4552
- for (const t of type.types) {
4579
+ let stringIndexInfo: IndexInfo;
4580
+ let numberIndexInfo: IndexInfo;
4581
+ let mixinTypes: Type[];
4582
+ const count = type.types.length;
4583
+ for (let i = 0; i < count; i++) {
4584
+ const t = type.types[i];
4585
+ // When a type T is preceded by a mixin constructor type, the return type of each construct signature
4586
+ // in T is intersected with the return type of the mixin constructor, and the mixin construct signature
4587
+ // is removed. For example, the intersection '{ new(...args: any[]) => A } & { new(s: string) => B }'
4588
+ // has a single construct signature 'new(s: string) => A & B'.
4589
+ let signatures = getSignaturesOfType(t, SignatureKind.Construct);
4590
+ if (i < count - 1 && isMixinConstructorType(t)) {
4591
+ (mixinTypes || (mixinTypes = [])).push(getReturnTypeOfSignature(signatures[0]));
4592
+ }
4593
+ else {
4594
+ if (mixinTypes) {
4595
+ signatures = map(signatures, s => {
4596
+ const clone = cloneSignature(s);
4597
+ clone.resolvedReturnType = getIntersectionType([...mixinTypes, getReturnTypeOfSignature(s)]);
4598
+ return clone;
4599
+ });
4600
+ mixinTypes = undefined;
4601
+ }
4602
+ constructSignatures = concatenate(constructSignatures, signatures);
4603
+ }
4553
4604
callSignatures = concatenate(callSignatures, getSignaturesOfType(t, SignatureKind.Call));
4554
- constructSignatures = concatenate(constructSignatures, getSignaturesOfType(t, SignatureKind.Construct));
4555
4605
stringIndexInfo = intersectIndexInfos(stringIndexInfo, getIndexInfoOfType(t, IndexKind.String));
4556
4606
numberIndexInfo = intersectIndexInfos(numberIndexInfo, getIndexInfoOfType(t, IndexKind.Number));
4557
4607
}
@@ -4593,7 +4643,7 @@ namespace ts {
4593
4643
constructSignatures = getDefaultConstructSignatures(classType);
4594
4644
}
4595
4645
const baseConstructorType = getBaseConstructorTypeOfClass(classType);
4596
- if (baseConstructorType.flags & (TypeFlags.Object | TypeFlags.Intersection)) {
4646
+ if (baseConstructorType.flags & (TypeFlags.Object | TypeFlags.Intersection | TypeFlags.TypeVariable )) {
4597
4647
members = createSymbolTable(getNamedMembers(members));
4598
4648
addInheritedMembers(members, getPropertiesOfType(baseConstructorType));
4599
4649
}
@@ -4890,6 +4940,7 @@ namespace ts {
4890
4940
4891
4941
function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: string): Symbol {
4892
4942
const types = containingType.types;
4943
+ const excludeModifiers = containingType.flags & TypeFlags.Union ? ModifierFlags.Private | ModifierFlags.Protected : 0;
4893
4944
let props: Symbol[];
4894
4945
// Flags we want to propagate to the result if they exist in all source symbols
4895
4946
let commonFlags = (containingType.flags & TypeFlags.Intersection) ? SymbolFlags.Optional : SymbolFlags.None;
@@ -4899,7 +4950,7 @@ namespace ts {
4899
4950
const type = getApparentType(current);
4900
4951
if (type !== unknownType) {
4901
4952
const prop = getPropertyOfType(type, name);
4902
- if (prop && !(getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected) )) {
4953
+ if (prop && !(getDeclarationModifierFlagsFromSymbol(prop) & excludeModifiers )) {
4903
4954
commonFlags &= prop.flags;
4904
4955
if (!props) {
4905
4956
props = [prop];
@@ -6965,9 +7016,12 @@ namespace ts {
6965
7016
result.properties = resolved.properties;
6966
7017
result.callSignatures = emptyArray;
6967
7018
result.constructSignatures = emptyArray;
6968
- type = result;
7019
+ return result;
6969
7020
}
6970
7021
}
7022
+ else if (type.flags & TypeFlags.Intersection) {
7023
+ return getIntersectionType(map((<IntersectionType>type).types, getTypeWithoutSignatures));
7024
+ }
6971
7025
return type;
6972
7026
}
6973
7027
@@ -18387,7 +18441,8 @@ namespace ts {
18387
18441
const baseTypes = getBaseTypes(type);
18388
18442
if (baseTypes.length && produceDiagnostics) {
18389
18443
const baseType = baseTypes[0];
18390
- const staticBaseType = getBaseConstructorTypeOfClass(type);
18444
+ const baseConstructorType = getBaseConstructorTypeOfClass(type);
18445
+ const staticBaseType = getApparentType(baseConstructorType);
18391
18446
checkBaseTypeAccessibility(staticBaseType, baseTypeNode);
18392
18447
checkSourceElement(baseTypeNode.expression);
18393
18448
if (baseTypeNode.typeArguments) {
@@ -18401,6 +18456,9 @@ namespace ts {
18401
18456
checkTypeAssignableTo(typeWithThis, getTypeWithThisArgument(baseType, type.thisType), node.name || node, Diagnostics.Class_0_incorrectly_extends_base_class_1);
18402
18457
checkTypeAssignableTo(staticType, getTypeWithoutSignatures(staticBaseType), node.name || node,
18403
18458
Diagnostics.Class_static_side_0_incorrectly_extends_base_class_static_side_1);
18459
+ if (baseConstructorType.flags & TypeFlags.TypeVariable && !isMixinConstructorType(staticType)) {
18460
+ error(node.name || node, Diagnostics.A_mixin_class_must_have_a_constructor_with_a_single_rest_parameter_of_type_any);
18461
+ }
18404
18462
18405
18463
if (baseType.symbol && baseType.symbol.valueDeclaration &&
18406
18464
!isInAmbientContext(baseType.symbol.valueDeclaration) &&
@@ -18410,7 +18468,7 @@ namespace ts {
18410
18468
}
18411
18469
}
18412
18470
18413
- if (!(staticBaseType.symbol && staticBaseType.symbol.flags & SymbolFlags.Class)) {
18471
+ if (!(staticBaseType.symbol && staticBaseType.symbol.flags & SymbolFlags.Class) && !(baseConstructorType.flags & TypeFlags.TypeVariable) ) {
18414
18472
// When the static base type is a "class-like" constructor function (but not actually a class), we verify
18415
18473
// that all instantiated base constructor signatures return the same type. We can simply compare the type
18416
18474
// references (as opposed to checking the structure of the types) because elsewhere we have already checked
0 commit comments