mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-14 19:16:17 -06:00
Contextually type 'this' in accessors of object literals
This commit is contained in:
parent
e3a0687327
commit
168d367b5e
@ -8983,11 +8983,19 @@ namespace ts {
|
||||
return regularNew;
|
||||
}
|
||||
|
||||
function getWidenedProperty(prop: Symbol): Symbol {
|
||||
const original = getTypeOfSymbol(prop);
|
||||
const widened = getWidenedType(original);
|
||||
return widened === original ? prop : createSymbolWithType(prop, widened);
|
||||
}
|
||||
|
||||
function getWidenedTypeOfObjectLiteral(type: Type): Type {
|
||||
const members = transformTypeOfMembers(type, prop => {
|
||||
const widened = getWidenedType(prop);
|
||||
return prop === widened ? prop : widened;
|
||||
});
|
||||
const members = createMap<Symbol>();
|
||||
for (let prop of getPropertiesOfObjectType(type)) {
|
||||
// Since get accessors already widen their return value there is no need to
|
||||
// widen accessor based properties here.
|
||||
members.set(prop.name, prop.flags & SymbolFlags.Property ? getWidenedProperty(prop) : prop);
|
||||
};
|
||||
const stringIndexInfo = getIndexInfoOfType(type, IndexKind.String);
|
||||
const numberIndexInfo = getIndexInfoOfType(type, IndexKind.Number);
|
||||
return createAnonymousType(type.symbol, members, emptyArray, emptyArray,
|
||||
@ -11471,7 +11479,9 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getContainingObjectLiteral(func: FunctionLikeDeclaration) {
|
||||
return func.kind === SyntaxKind.MethodDeclaration && func.parent.kind === SyntaxKind.ObjectLiteralExpression ? <ObjectLiteralExpression>func.parent :
|
||||
return (func.kind === SyntaxKind.MethodDeclaration ||
|
||||
func.kind === SyntaxKind.GetAccessor ||
|
||||
func.kind === SyntaxKind.SetAccessor) && func.parent.kind === SyntaxKind.ObjectLiteralExpression ? <ObjectLiteralExpression>func.parent :
|
||||
func.kind === SyntaxKind.FunctionExpression && func.parent.kind === SyntaxKind.PropertyAssignment ? <ObjectLiteralExpression>func.parent.parent :
|
||||
undefined;
|
||||
}
|
||||
@ -11487,7 +11497,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getContextualThisParameterType(func: FunctionLikeDeclaration): Type {
|
||||
if (isContextSensitiveFunctionOrObjectLiteralMethod(func) && func.kind !== SyntaxKind.ArrowFunction) {
|
||||
if (func.kind === SyntaxKind.ArrowFunction) {
|
||||
return undefined;
|
||||
}
|
||||
if (isContextSensitiveFunctionOrObjectLiteralMethod(func)) {
|
||||
const contextualSignature = getContextualSignature(func);
|
||||
if (contextualSignature) {
|
||||
const thisParameter = contextualSignature.thisParameter;
|
||||
@ -11495,36 +11508,36 @@ namespace ts {
|
||||
return getTypeOfSymbol(thisParameter);
|
||||
}
|
||||
}
|
||||
const containingLiteral = getContainingObjectLiteral(func);
|
||||
if (containingLiteral) {
|
||||
// We have an object literal method. Check if the containing object literal has a contextual type
|
||||
// and if that contextual type is or includes a ThisType<T>. If so, T is the contextual type for
|
||||
// 'this'. We continue looking in any directly enclosing object literals.
|
||||
let objectLiteral = containingLiteral;
|
||||
while (true) {
|
||||
const type = getApparentTypeOfContextualType(objectLiteral);
|
||||
if (type) {
|
||||
const thisType = getThisTypeFromContextualType(type);
|
||||
if (thisType) {
|
||||
return thisType;
|
||||
}
|
||||
}
|
||||
const containingLiteral = getContainingObjectLiteral(func);
|
||||
if (containingLiteral) {
|
||||
// We have an object literal method. Check if the containing object literal has a contextual type
|
||||
// and if that contextual type is or includes a ThisType<T>. If so, T is the contextual type for
|
||||
// 'this'. We continue looking in any directly enclosing object literals.
|
||||
let objectLiteral = containingLiteral;
|
||||
while (true) {
|
||||
const type = getApparentTypeOfContextualType(objectLiteral);
|
||||
if (type) {
|
||||
const thisType = getThisTypeFromContextualType(type);
|
||||
if (thisType) {
|
||||
return thisType;
|
||||
}
|
||||
if (objectLiteral.parent.kind !== SyntaxKind.PropertyAssignment) {
|
||||
break;
|
||||
}
|
||||
objectLiteral = <ObjectLiteralExpression>objectLiteral.parent.parent;
|
||||
}
|
||||
// There was no contextual ThisType<T> for the containing object literal, so the contextual type
|
||||
// for 'this' is the type of the object literal itself.
|
||||
return checkExpressionCached(containingLiteral);
|
||||
if (objectLiteral.parent.kind !== SyntaxKind.PropertyAssignment) {
|
||||
break;
|
||||
}
|
||||
objectLiteral = <ObjectLiteralExpression>objectLiteral.parent.parent;
|
||||
}
|
||||
// In an assignment of the form 'obj.xxx = function(...)' or 'obj[xxx] = function(...)', the
|
||||
// contextual type for 'this' is 'obj'.
|
||||
if (func.parent.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>func.parent).operatorToken.kind === SyntaxKind.EqualsToken) {
|
||||
const target = (<BinaryExpression>func.parent).left;
|
||||
if (target.kind === SyntaxKind.PropertyAccessExpression || target.kind === SyntaxKind.ElementAccessExpression) {
|
||||
return checkExpressionCached((<PropertyAccessExpression | ElementAccessExpression>target).expression);
|
||||
}
|
||||
// There was no contextual ThisType<T> for the containing object literal, so the contextual type
|
||||
// for 'this' is the type of the object literal itself.
|
||||
return checkExpressionCached(containingLiteral);
|
||||
}
|
||||
// In an assignment of the form 'obj.xxx = function(...)' or 'obj[xxx] = function(...)', the
|
||||
// contextual type for 'this' is 'obj'.
|
||||
if (func.parent.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>func.parent).operatorToken.kind === SyntaxKind.EqualsToken) {
|
||||
const target = (<BinaryExpression>func.parent).left;
|
||||
if (target.kind === SyntaxKind.PropertyAccessExpression || target.kind === SyntaxKind.ElementAccessExpression) {
|
||||
return checkExpressionCached((<PropertyAccessExpression | ElementAccessExpression>target).expression);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
@ -12287,7 +12300,7 @@ namespace ts {
|
||||
// A set accessor declaration is processed in the same manner
|
||||
// as an ordinary function declaration with a single parameter and a Void return type.
|
||||
Debug.assert(memberDecl.kind === SyntaxKind.GetAccessor || memberDecl.kind === SyntaxKind.SetAccessor);
|
||||
checkAccessorDeclaration(<AccessorDeclaration>memberDecl);
|
||||
checkNodeDeferred(memberDecl);
|
||||
}
|
||||
|
||||
if (hasDynamicName(memberDecl)) {
|
||||
@ -16942,13 +16955,8 @@ namespace ts {
|
||||
checkAllCodePathsInNonVoidFunctionReturnOrThrow(node, returnType);
|
||||
}
|
||||
}
|
||||
if (node.parent.kind !== SyntaxKind.ObjectLiteralExpression) {
|
||||
checkSourceElement(node.body);
|
||||
registerForUnusedIdentifiersCheck(node);
|
||||
}
|
||||
else {
|
||||
checkNodeDeferred(node);
|
||||
}
|
||||
checkSourceElement(node.body);
|
||||
registerForUnusedIdentifiersCheck(node);
|
||||
}
|
||||
|
||||
function checkAccessorDeclarationTypesIdentical(first: AccessorDeclaration, second: AccessorDeclaration, getAnnotatedType: (a: AccessorDeclaration) => Type, message: DiagnosticMessage) {
|
||||
@ -16959,11 +16967,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function checkAccessorDeferred(node: AccessorDeclaration) {
|
||||
checkSourceElement(node.body);
|
||||
registerForUnusedIdentifiersCheck(node);
|
||||
}
|
||||
|
||||
function checkMissingDeclaration(node: Node) {
|
||||
checkDecorators(node);
|
||||
}
|
||||
@ -20630,7 +20633,7 @@ namespace ts {
|
||||
break;
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
checkAccessorDeferred(<AccessorDeclaration>node);
|
||||
checkAccessorDeclaration(<AccessorDeclaration>node);
|
||||
break;
|
||||
case SyntaxKind.ClassExpression:
|
||||
checkClassExpressionDeferred(<ClassExpression>node);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user