@@ -97,8 +97,8 @@ module ts {
97
97
let anyFunctionType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
98
98
let noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
99
99
100
- let anySignature = createSignature(undefined, undefined, emptyArray, anyType, 0, false, false);
101
- let unknownSignature = createSignature(undefined, undefined, emptyArray, unknownType, 0, false, false);
100
+ let anySignature = createSignature(undefined, undefined, emptyArray, anyType, undefined, 0, false, false);
101
+ let unknownSignature = createSignature(undefined, undefined, emptyArray, unknownType, undefined, 0, false, false);
102
102
103
103
let globals: SymbolTable = {};
104
104
@@ -2766,7 +2766,7 @@ module ts {
2766
2766
2767
2767
function resolveDeclaredMembers(type: InterfaceType): InterfaceTypeWithDeclaredMembers {
2768
2768
if (!(<InterfaceTypeWithDeclaredMembers>type).declaredProperties) {
2769
- var symbol = type.symbol;
2769
+ let symbol = type.symbol;
2770
2770
(<InterfaceTypeWithDeclaredMembers>type).declaredProperties = getNamedMembers(symbol.members);
2771
2771
(<InterfaceTypeWithDeclaredMembers>type).declaredCallSignatures = getSignaturesOfSymbol(symbol.members["__call"]);
2772
2772
(<InterfaceTypeWithDeclaredMembers>type).declaredConstructSignatures = getSignaturesOfSymbol(symbol.members["__new"]);
@@ -2776,7 +2776,7 @@ module ts {
2776
2776
return <InterfaceTypeWithDeclaredMembers>type;
2777
2777
}
2778
2778
2779
- function resolveClassOrInterfaceMembers(type: InterfaceType): void {
2779
+ function resolveClassOrInterfaceMembers(type: InterfaceType) {
2780
2780
let target = resolveDeclaredMembers(type);
2781
2781
let members = target.symbol.members;
2782
2782
let callSignatures = target.declaredCallSignatures;
@@ -2817,20 +2817,21 @@ module ts {
2817
2817
}
2818
2818
2819
2819
function createSignature(declaration: SignatureDeclaration, typeParameters: TypeParameter[], parameters: Symbol[],
2820
- resolvedReturnType: Type, minArgumentCount: number, hasRestParameter: boolean, hasStringLiterals: boolean): Signature {
2820
+ resolvedReturnType: Type, typePredicate: TypePredicate, minArgumentCount: number, hasRestParameter: boolean, hasStringLiterals: boolean): Signature {
2821
2821
let sig = new Signature(checker);
2822
2822
sig.declaration = declaration;
2823
2823
sig.typeParameters = typeParameters;
2824
2824
sig.parameters = parameters;
2825
2825
sig.resolvedReturnType = resolvedReturnType;
2826
+ sig.typePredicate = typePredicate;
2826
2827
sig.minArgumentCount = minArgumentCount;
2827
2828
sig.hasRestParameter = hasRestParameter;
2828
2829
sig.hasStringLiterals = hasStringLiterals;
2829
2830
return sig;
2830
2831
}
2831
2832
2832
2833
function cloneSignature(sig: Signature): Signature {
2833
- return createSignature(sig.declaration, sig.typeParameters, sig.parameters, sig.resolvedReturnType,
2834
+ return createSignature(sig.declaration, sig.typeParameters, sig.parameters, sig.resolvedReturnType, sig.typePredicate,
2834
2835
sig.minArgumentCount, sig.hasRestParameter, sig.hasStringLiterals);
2835
2836
}
2836
2837
@@ -2847,7 +2848,7 @@ module ts {
2847
2848
return signature;
2848
2849
});
2849
2850
}
2850
- return [createSignature(undefined, classType.localTypeParameters, emptyArray, classType, 0, false, false)];
2851
+ return [createSignature(undefined, classType.localTypeParameters, emptyArray, classType, undefined, 0, false, false)];
2851
2852
}
2852
2853
2853
2854
function createTupleTypeMemberSymbols(memberTypes: Type[]): SymbolTable {
@@ -3219,7 +3220,24 @@ module ts {
3219
3220
}
3220
3221
3221
3222
let returnType: Type;
3222
- if (classType) {
3223
+ let typePredicate: TypePredicate;
3224
+ if (declaration.typePredicate) {
3225
+ returnType = booleanType;
3226
+ let typePredicateNode = declaration.typePredicate;
3227
+ let links = getNodeLinks(typePredicateNode);
3228
+ if (links.typePredicateParameterIndex === undefined) {
3229
+ links.typePredicateParameterIndex = getTypePredicateParameterIndex(declaration.parameters, typePredicateNode.parameterName);
3230
+ }
3231
+ if (!links.typeFromTypePredicate) {
3232
+ links.typeFromTypePredicate = getTypeFromTypeNode(declaration.typePredicate.type);
3233
+ }
3234
+ typePredicate = {
3235
+ parameterName: typePredicateNode.parameterName ? typePredicateNode.parameterName.text : undefined,
3236
+ parameterIndex: typePredicateNode.parameterName ? links.typePredicateParameterIndex : undefined,
3237
+ type: links.typeFromTypePredicate
3238
+ };
3239
+ }
3240
+ else if (classType) {
3223
3241
returnType = classType;
3224
3242
}
3225
3243
else if (declaration.type) {
@@ -3238,7 +3256,7 @@ module ts {
3238
3256
}
3239
3257
}
3240
3258
3241
- links.resolvedSignature = createSignature(declaration, typeParameters, parameters, returnType,
3259
+ links.resolvedSignature = createSignature(declaration, typeParameters, parameters, returnType, typePredicate,
3242
3260
minArgumentCount, hasRestParameters(declaration), hasStringLiterals);
3243
3261
}
3244
3262
return links.resolvedSignature;
@@ -3944,9 +3962,13 @@ module ts {
3944
3962
freshTypeParameters = instantiateList(signature.typeParameters, mapper, instantiateTypeParameter);
3945
3963
mapper = combineTypeMappers(createTypeMapper(signature.typeParameters, freshTypeParameters), mapper);
3946
3964
}
3965
+ if (signature.typePredicate) {
3966
+ signature.typePredicate.type = instantiateType(signature.typePredicate.type, mapper);
3967
+ }
3947
3968
let result = createSignature(signature.declaration, freshTypeParameters,
3948
3969
instantiateList(signature.parameters, mapper, instantiateSymbol),
3949
3970
signature.resolvedReturnType ? instantiateType(signature.resolvedReturnType, mapper) : undefined,
3971
+ signature.typePredicate,
3950
3972
signature.minArgumentCount, signature.hasRestParameter, signature.hasStringLiterals);
3951
3973
result.target = signature;
3952
3974
result.mapper = mapper;
@@ -4614,6 +4636,43 @@ module ts {
4614
4636
}
4615
4637
result &= related;
4616
4638
}
4639
+
4640
+ if (source.typePredicate && target.typePredicate) {
4641
+ if (source.typePredicate.parameterIndex !== target.typePredicate.parameterIndex ||
4642
+ source.typePredicate.type.symbol !== target.typePredicate.type.symbol) {
4643
+
4644
+ if (reportErrors) {
4645
+ let sourceParamText = source.typePredicate.parameterName;
4646
+ let targetParamText = target.typePredicate.parameterName;
4647
+ let sourceTypeText = typeToString(source.typePredicate.type);
4648
+ let targetTypeText = typeToString(target.typePredicate.type);
4649
+
4650
+ if (source.typePredicate.parameterIndex !== target.typePredicate.parameterIndex) {
4651
+ reportError(Diagnostics.Parameter_index_from_0_does_not_match_the_parameter_index_from_1,
4652
+ sourceParamText,
4653
+ targetParamText);
4654
+ }
4655
+ if (source.typePredicate.type.symbol !== target.typePredicate.type.symbol) {
4656
+ reportError(Diagnostics.Type_0_is_not_assignable_to_type_1,
4657
+ sourceTypeText,
4658
+ targetTypeText);
4659
+ }
4660
+
4661
+ reportError(Diagnostics.Type_guard_annotation_0_is_not_assignable_to_1,
4662
+ `${sourceParamText} is ${sourceTypeText}`,
4663
+ `${targetParamText} is ${targetTypeText}`);
4664
+ }
4665
+
4666
+ return Ternary.False;
4667
+ }
4668
+ }
4669
+ else if (!source.typePredicate && target.typePredicate) {
4670
+ if (reportErrors) {
4671
+ reportError(Diagnostics.A_non_type_guard_function_is_not_assignable_to_a_type_guard_function);
4672
+ }
4673
+ return Ternary.False;
4674
+ }
4675
+
4617
4676
let t = getReturnTypeOfSignature(target);
4618
4677
if (t === voidType) return result;
4619
4678
let s = getReturnTypeOfSignature(source);
@@ -5146,6 +5205,13 @@ module ts {
5146
5205
5147
5206
function inferFromSignature(source: Signature, target: Signature) {
5148
5207
forEachMatchingParameterType(source, target, inferFromTypes);
5208
+ if (source.typePredicate &&
5209
+ target.typePredicate &&
5210
+ target.typePredicate.parameterIndex === source.typePredicate.parameterIndex) {
5211
+
5212
+ inferFromTypes(source.typePredicate.type, target.typePredicate.type);
5213
+ return;
5214
+ }
5149
5215
inferFromTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target));
5150
5216
}
5151
5217
@@ -5527,7 +5593,7 @@ module ts {
5527
5593
let targetType: Type;
5528
5594
let prototypeProperty = getPropertyOfType(rightType, "prototype");
5529
5595
if (prototypeProperty) {
5530
- // Target type is type of the protoype property
5596
+ // Target type is type of the prototype property
5531
5597
let prototypePropertyType = getTypeOfSymbol(prototypeProperty);
5532
5598
if (prototypePropertyType !== anyType) {
5533
5599
targetType = prototypePropertyType;
@@ -5543,7 +5609,6 @@ module ts {
5543
5609
else if (rightType.flags & TypeFlags.Anonymous) {
5544
5610
constructSignatures = getSignaturesOfType(rightType, SignatureKind.Construct);
5545
5611
}
5546
-
5547
5612
if (constructSignatures && constructSignatures.length) {
5548
5613
targetType = getUnionType(map(constructSignatures, signature => getReturnTypeOfSignature(getErasedSignature(signature))));
5549
5614
}
@@ -5563,10 +5628,38 @@ module ts {
5563
5628
return type;
5564
5629
}
5565
5630
5631
+ function narrowTypeByTypePredicate(type: Type, expr: CallExpression, assumeTrue: boolean): Type {
5632
+ if (type.flags & TypeFlags.Any) {
5633
+ return type;
5634
+ }
5635
+ let signature = getResolvedSignature(expr);
5636
+ if (!assumeTrue) {
5637
+ if (type.flags & TypeFlags.Union && signature.typePredicate) {
5638
+ return getUnionType(filter((<UnionType>type).types, t => !isTypeSubtypeOf(t, signature.typePredicate.type)));
5639
+ }
5640
+ return type;
5641
+ }
5642
+ if (signature.typePredicate) {
5643
+ if (expr.arguments && expr.arguments[signature.typePredicate.parameterIndex]) {
5644
+ if (getSymbolAtLocation(expr.arguments[signature.typePredicate.parameterIndex]) === symbol) {
5645
+ if (isTypeSubtypeOf(signature.typePredicate.type, type)) {
5646
+ return signature.typePredicate.type;
5647
+ }
5648
+ if (type.flags & TypeFlags.Union) {
5649
+ return getUnionType(filter((<UnionType>type).types, t => isTypeSubtypeOf(t, signature.typePredicate.type)));
5650
+ }
5651
+ }
5652
+ }
5653
+ }
5654
+ return type;
5655
+ }
5656
+
5566
5657
// Narrow the given type based on the given expression having the assumed boolean value. The returned type
5567
5658
// will be a subtype or the same type as the argument.
5568
5659
function narrowType(type: Type, expr: Expression, assumeTrue: boolean): Type {
5569
5660
switch (expr.kind) {
5661
+ case SyntaxKind.CallExpression:
5662
+ return narrowTypeByTypePredicate(type, <CallExpression>expr, assumeTrue);
5570
5663
case SyntaxKind.ParenthesizedExpression:
5571
5664
return narrowType(type, (<ParenthesizedExpression>expr).expression, assumeTrue);
5572
5665
case SyntaxKind.BinaryExpression:
@@ -8468,6 +8561,20 @@ module ts {
8468
8561
node.kind === SyntaxKind.FunctionExpression;
8469
8562
}
8470
8563
8564
+ function getTypePredicateParameterIndex(parameterList: NodeArray<ParameterDeclaration>, parameter: Identifier): number {
8565
+ let index = -1;
8566
+ if (parameterList) {
8567
+ for (let i = 0; i < parameterList.length; i++) {
8568
+ let param = parameterList[i];
8569
+ if (param.name.kind === SyntaxKind.Identifier &&
8570
+ (<Identifier>param.name).text === parameter.text) {
8571
+
8572
+ return i;
8573
+ }
8574
+ }
8575
+ }
8576
+ }
8577
+
8471
8578
function checkSignatureDeclaration(node: SignatureDeclaration) {
8472
8579
// Grammar checking
8473
8580
if (node.kind === SyntaxKind.IndexSignature) {
@@ -8488,6 +8595,27 @@ module ts {
8488
8595
checkSourceElement(node.type);
8489
8596
}
8490
8597
8598
+ if (node.typePredicate) {
8599
+ let links = getNodeLinks(node.typePredicate);
8600
+ if (links.typePredicateParameterIndex === undefined) {
8601
+ links.typePredicateParameterIndex = getTypePredicateParameterIndex(node.parameters, node.typePredicate.parameterName);
8602
+ }
8603
+ if (!links.typeFromTypePredicate) {
8604
+ links.typeFromTypePredicate = getTypeFromTypeNode(node.typePredicate.type);
8605
+ }
8606
+ if (links.typePredicateParameterIndex >= 0) {
8607
+ checkTypeAssignableTo(
8608
+ links.typeFromTypePredicate,
8609
+ getTypeAtLocation(node.parameters[links.typePredicateParameterIndex]),
8610
+ node.typePredicate.type);
8611
+ }
8612
+ else if(node.typePredicate.parameterName) {
8613
+ error(node.typePredicate.parameterName,
8614
+ Diagnostics.Cannot_find_parameter_0,
8615
+ node.typePredicate.parameterName.text);
8616
+ }
8617
+ }
8618
+
8491
8619
if (produceDiagnostics) {
8492
8620
checkCollisionWithArgumentsInGeneratedCode(node);
8493
8621
if (compilerOptions.noImplicitAny && !node.type) {
@@ -10047,9 +10175,6 @@ module ts {
10047
10175
if (node.expression) {
10048
10176
let func = getContainingFunction(node);
10049
10177
if (func) {
10050
- let returnType = getReturnTypeOfSignature(getSignatureFromDeclaration(func));
10051
- let exprType = checkExpressionCached(node.expression);
10052
-
10053
10178
if (func.asteriskToken) {
10054
10179
// A generator does not need its return expressions checked against its return type.
10055
10180
// Instead, the yield expressions are checked against the element type.
@@ -10058,6 +10183,13 @@ module ts {
10058
10183
return;
10059
10184
}
10060
10185
10186
+ let signature = getSignatureFromDeclaration(func);
10187
+ let exprType = checkExpressionCached(node.expression);
10188
+ if (signature.typePredicate && exprType !== booleanType) {
10189
+ error(node.expression, Diagnostics.A_type_guard_function_can_only_return_a_boolean);
10190
+ }
10191
+ let returnType = getReturnTypeOfSignature(signature);
10192
+
10061
10193
if (func.kind === SyntaxKind.SetAccessor) {
10062
10194
error(node.expression, Diagnostics.Setters_cannot_return_a_value);
10063
10195
}
0 commit comments