Reimplemented Nathan's changes.

This commit is contained in:
Daniel Rosenwasser 2016-08-25 15:48:08 -07:00
parent 29c18058d6
commit 4f84639e47
2 changed files with 65 additions and 10 deletions

View File

@ -3432,6 +3432,44 @@ namespace ts {
return unknownType;
}
function getTypeOfBasePropertyDeclaration(declaration: PropertyDeclaration) {
if (declaration.parent.kind === SyntaxKind.ClassDeclaration) {
const parent = <ClassLikeDeclaration>declaration.parent;
const propertyName = declaration.symbol.name;
const extendedPropertyType = getSinglePropertyTypeOfTypes(getBaseTypes(<InterfaceType>getTypeOfSymbol(getSymbolOfNode(parent))), propertyName);
if (extendedPropertyType) {
return extendedPropertyType;
}
const implementedTypeNodes = getClassImplementsHeritageClauseElements(parent);
if (implementedTypeNodes) {
return getSinglePropertyTypeOfTypes(map(implementedTypeNodes, getTypeFromTypeReference), propertyName);
}
}
return undefined;
}
function getSinglePropertyTypeOfTypes(types: Type[], propertyName: string) {
let result: Type;
for (const t of types) {
if (t !== unknownType) {
const property = getPropertyOfType(t, propertyName);
if (!property || property.valueDeclaration.flags & NodeFlags.Private) {
continue;
}
if (property.name === propertyName) {
const propertyType = getTypeOfSymbol(property);
if (result && result !== propertyType) {
// if there's more than one matching property, return undefined
return undefined;
}
result = propertyType;
}
}
}
return result;
}
function getTargetType(type: ObjectType): Type {
return type.flags & TypeFlags.Reference ? (<TypeReference>type).target : type;
}
@ -5898,7 +5936,7 @@ namespace ts {
// Returns true if the given expression contains (at any level of nesting) a function or arrow expression
// that is subject to contextual typing.
function isContextSensitive(node: Expression | MethodDeclaration | ObjectLiteralElement): boolean {
Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node));
Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isMethod(node));
switch (node.kind) {
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
@ -5931,8 +5969,8 @@ namespace ts {
return !node.typeParameters && areAllParametersUntyped && !isNullaryArrow;
}
function isContextSensitiveFunctionOrObjectLiteralMethod(func: Node): func is FunctionExpression | MethodDeclaration {
return (isFunctionExpressionOrArrowFunction(func) || isObjectLiteralMethod(func)) && isContextSensitiveFunctionLikeDeclaration(func);
function isContextSensitiveFunctionOrMethod(func: Node): func is FunctionExpression | MethodDeclaration {
return (isFunctionExpressionOrArrowFunction(func) || isMethod(func)) && isContextSensitiveFunctionLikeDeclaration(func);
}
function getTypeWithoutSignatures(type: Type): Type {
@ -9374,7 +9412,7 @@ namespace ts {
}
function getContextualThisParameter(func: FunctionLikeDeclaration): Symbol {
if (isContextSensitiveFunctionOrObjectLiteralMethod(func) && func.kind !== SyntaxKind.ArrowFunction) {
if (isContextSensitiveFunctionOrMethod(func) && func.kind !== SyntaxKind.ArrowFunction) {
const contextualSignature = getContextualSignature(func);
if (contextualSignature) {
return contextualSignature.thisParameter;
@ -9387,7 +9425,7 @@ namespace ts {
// Return contextual type of parameter or undefined if no contextual type is available
function getContextuallyTypedParameterType(parameter: ParameterDeclaration): Type {
const func = parameter.parent;
if (isContextSensitiveFunctionOrObjectLiteralMethod(func)) {
if (isContextSensitiveFunctionOrMethod(func)) {
const iife = getImmediatelyInvokedFunctionExpression(func);
if (iife) {
const indexOfParameter = indexOf(func.parameters, parameter);
@ -9447,6 +9485,12 @@ namespace ts {
return type;
}
}
if (declaration.kind === SyntaxKind.PropertyDeclaration) {
const type = getTypeOfBasePropertyDeclaration(<PropertyDeclaration>declaration);
if (type) {
return type;
}
}
if (isBindingPattern(declaration.name)) {
return getTypeFromBindingPattern(<BindingPattern>declaration.name, /*includePatternInType*/ true, /*reportErrors*/ false);
}
@ -9815,15 +9859,23 @@ namespace ts {
function getContextualSignatureForFunctionLikeDeclaration(node: FunctionLikeDeclaration): Signature {
// Only function expressions, arrow functions, and object literal methods are contextually typed.
return isFunctionExpressionOrArrowFunction(node) || isObjectLiteralMethod(node)
return isFunctionExpressionOrArrowFunction(node) || isMethod(node)
? getContextualSignature(<FunctionExpression>node)
: undefined;
}
function getContextualTypeForFunctionLikeDeclaration(node: FunctionExpression | MethodDeclaration) {
return isObjectLiteralMethod(node) ?
getContextualTypeForObjectLiteralMethod(node) :
getApparentTypeOfContextualType(node);
let type: Type;
if (isFunctionExpressionOrArrowFunction(node)) {
type = getApparentTypeOfContextualType(node);
}
else if (isObjectLiteralMethod(node)) {
type = getContextualTypeForObjectLiteralMethod(node);
}
else if (isMethod(node)) {
type = getTypeOfBasePropertyDeclaration(node);
}
return type;
}
// Return the contextual signature for a given expression node. A contextual type provides a
@ -9832,7 +9884,6 @@ namespace ts {
// all identical ignoring their return type, the result is same signature but with return type as
// union type of return types from these signatures
function getContextualSignature(node: FunctionExpression | MethodDeclaration): Signature {
Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node));
const type = getContextualTypeForFunctionLikeDeclaration(node);
if (!type) {
return undefined;

View File

@ -864,6 +864,10 @@ namespace ts {
return predicate && predicate.kind === TypePredicateKind.Identifier;
}
export function isMethod(node: Node): node is MethodDeclaration {
return node && node.kind === SyntaxKind.MethodDeclaration;
}
export function isThisTypePredicate(predicate: TypePredicate): predicate is ThisTypePredicate {
return predicate && predicate.kind === TypePredicateKind.This;
}