mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-09 02:30:15 -06:00
Added --noImplicitThis code fix for functions used as object properties (#31138)
* Added --noImplicitThis code fix for functions used as object properties Before trying out all the various possibilities for where these functions could be used, I figured I'd start out with a relatively simple use case to verify this is the right approach. Is it? 😄 Starts on #28964. * Fixed function expression names; included new baselines * Got JSDocs to work, hooray! * Added test for 'any' case of no function uses * Refactored for inferFunctionReferencesFromUsage * Fixed inference bug: undefined references cause parameters to default * Removed dead code comments
This commit is contained in:
parent
7f65be44c1
commit
ca00b3248b
@ -4990,7 +4990,10 @@
|
||||
"category": "Message",
|
||||
"code": 95079
|
||||
},
|
||||
|
||||
"Infer 'this' type of '{0}' from usage": {
|
||||
"category": "Message",
|
||||
"code": 95080
|
||||
},
|
||||
"No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer.": {
|
||||
"category": "Error",
|
||||
"code": 18004
|
||||
|
||||
@ -2204,6 +2204,13 @@ namespace ts {
|
||||
return tag;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function createJSDocThisTag(typeExpression?: JSDocTypeExpression): JSDocThisTag {
|
||||
const tag = createJSDocTag<JSDocThisTag>(SyntaxKind.JSDocThisTag, "this");
|
||||
tag.typeExpression = typeExpression;
|
||||
return tag;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function createJSDocParamTag(name: EntityName, isBracketed: boolean, typeExpression?: JSDocTypeExpression, comment?: string): JSDocParameterTag {
|
||||
const tag = createJSDocTag<JSDocParameterTag>(SyntaxKind.JSDocParameterTag, "param");
|
||||
|
||||
@ -5187,6 +5187,9 @@ namespace ts {
|
||||
return node.parent.left.name;
|
||||
}
|
||||
}
|
||||
else if (isVariableDeclaration(node.parent) && isIdentifier(node.parent.name)) {
|
||||
return node.parent.name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -42,6 +42,9 @@ namespace ts.codefix {
|
||||
|
||||
// Property declarations
|
||||
Diagnostics.Member_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage.code,
|
||||
|
||||
// Function expressions and declarations
|
||||
Diagnostics.this_implicitly_has_type_any_because_it_does_not_have_a_type_annotation.code,
|
||||
];
|
||||
registerCodeFix({
|
||||
errorCodes,
|
||||
@ -73,6 +76,8 @@ namespace ts.codefix {
|
||||
case Diagnostics.Rest_parameter_0_implicitly_has_an_any_type.code:
|
||||
case Diagnostics.Rest_parameter_0_implicitly_has_an_any_type_but_a_better_type_may_be_inferred_from_usage.code:
|
||||
return Diagnostics.Infer_parameter_types_from_usage;
|
||||
case Diagnostics.this_implicitly_has_type_any_because_it_does_not_have_a_type_annotation.code:
|
||||
return Diagnostics.Infer_this_type_of_0_from_usage;
|
||||
default:
|
||||
return Diagnostics.Infer_type_of_0_from_usage;
|
||||
}
|
||||
@ -176,6 +181,14 @@ namespace ts.codefix {
|
||||
}
|
||||
return undefined;
|
||||
|
||||
// Function 'this'
|
||||
case Diagnostics.this_implicitly_has_type_any_because_it_does_not_have_a_type_annotation.code:
|
||||
if (textChanges.isThisTypeAnnotatable(containingFunction) && markSeen(containingFunction)) {
|
||||
annotateThis(changes, sourceFile, containingFunction, program, host, cancellationToken);
|
||||
return containingFunction;
|
||||
}
|
||||
return undefined;
|
||||
|
||||
default:
|
||||
return Debug.fail(String(errorCode));
|
||||
}
|
||||
@ -191,7 +204,9 @@ namespace ts.codefix {
|
||||
if (!isIdentifier(parameterDeclaration.name)) {
|
||||
return;
|
||||
}
|
||||
const parameterInferences = inferTypeForParametersFromUsage(containingFunction, sourceFile, program, cancellationToken) ||
|
||||
|
||||
const references = inferFunctionReferencesFromUsage(containingFunction, sourceFile, program, cancellationToken);
|
||||
const parameterInferences = InferFromReference.inferTypeForParametersFromReferences(references, containingFunction, program, cancellationToken) ||
|
||||
containingFunction.parameters.map<ParameterInference>(p => ({
|
||||
declaration: p,
|
||||
type: isIdentifier(p.name) ? inferTypeForVariableFromUsage(p.name, program, cancellationToken) : program.getTypeChecker().getAnyType()
|
||||
@ -213,6 +228,36 @@ namespace ts.codefix {
|
||||
}
|
||||
}
|
||||
|
||||
function annotateThis(changes: textChanges.ChangeTracker, sourceFile: SourceFile, containingFunction: textChanges.ThisTypeAnnotatable, program: Program, host: LanguageServiceHost, cancellationToken: CancellationToken) {
|
||||
const references = inferFunctionReferencesFromUsage(containingFunction, sourceFile, program, cancellationToken);
|
||||
if (!references) {
|
||||
return;
|
||||
}
|
||||
|
||||
const thisInference = InferFromReference.inferTypeForThisFromReferences(references, program, cancellationToken);
|
||||
if (!thisInference) {
|
||||
return;
|
||||
}
|
||||
|
||||
const typeNode = getTypeNodeIfAccessible(thisInference, containingFunction, program, host);
|
||||
if (!typeNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isInJSFile(containingFunction)) {
|
||||
annotateJSDocThis(changes, sourceFile, containingFunction, typeNode);
|
||||
}
|
||||
else {
|
||||
changes.tryInsertThisTypeAnnotation(sourceFile, containingFunction, typeNode);
|
||||
}
|
||||
}
|
||||
|
||||
function annotateJSDocThis(changes: textChanges.ChangeTracker, sourceFile: SourceFile, containingFunction: FunctionLike, typeNode: TypeNode) {
|
||||
addJSDocTags(changes, sourceFile, containingFunction, [
|
||||
createJSDocThisTag(createJSDocTypeExpression(typeNode)),
|
||||
]);
|
||||
}
|
||||
|
||||
function annotateSetAccessor(changes: textChanges.ChangeTracker, sourceFile: SourceFile, setAccessorDeclaration: SetAccessorDeclaration, program: Program, host: LanguageServiceHost, cancellationToken: CancellationToken): void {
|
||||
const param = firstOrUndefined(setAccessorDeclaration.parameters);
|
||||
if (param && isIdentifier(setAccessorDeclaration.name) && isIdentifier(param.name)) {
|
||||
@ -317,7 +362,7 @@ namespace ts.codefix {
|
||||
return InferFromReference.unifyFromContext(types, checker);
|
||||
}
|
||||
|
||||
function inferTypeForParametersFromUsage(containingFunction: FunctionLike, sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): ParameterInference[] | undefined {
|
||||
function inferFunctionReferencesFromUsage(containingFunction: FunctionLike, sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): ReadonlyArray<Identifier> | undefined {
|
||||
let searchToken;
|
||||
switch (containingFunction.kind) {
|
||||
case SyntaxKind.Constructor:
|
||||
@ -335,9 +380,12 @@ namespace ts.codefix {
|
||||
searchToken = containingFunction.name;
|
||||
break;
|
||||
}
|
||||
if (searchToken) {
|
||||
return InferFromReference.inferTypeForParametersFromReferences(getReferences(searchToken, program, cancellationToken), containingFunction, program, cancellationToken);
|
||||
|
||||
if (!searchToken) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return getReferences(searchToken, program, cancellationToken);
|
||||
}
|
||||
|
||||
interface ParameterInference {
|
||||
@ -364,6 +412,7 @@ namespace ts.codefix {
|
||||
constructContexts?: CallContext[];
|
||||
numberIndexContext?: UsageContext;
|
||||
stringIndexContext?: UsageContext;
|
||||
candidateThisTypes?: Type[];
|
||||
}
|
||||
|
||||
export function inferTypesFromReferences(references: ReadonlyArray<Identifier>, checker: TypeChecker, cancellationToken: CancellationToken): Type[] {
|
||||
@ -375,15 +424,12 @@ namespace ts.codefix {
|
||||
return inferFromContext(usageContext, checker);
|
||||
}
|
||||
|
||||
export function inferTypeForParametersFromReferences(references: ReadonlyArray<Identifier>, declaration: FunctionLike, program: Program, cancellationToken: CancellationToken): ParameterInference[] | undefined {
|
||||
const checker = program.getTypeChecker();
|
||||
if (references.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
if (!declaration.parameters) {
|
||||
export function inferTypeForParametersFromReferences(references: ReadonlyArray<Identifier> | undefined, declaration: FunctionLike, program: Program, cancellationToken: CancellationToken): ParameterInference[] | undefined {
|
||||
if (references === undefined || references.length === 0 || !declaration.parameters) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const checker = program.getTypeChecker();
|
||||
const usageContext: UsageContext = {};
|
||||
for (const reference of references) {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
@ -421,6 +467,22 @@ namespace ts.codefix {
|
||||
});
|
||||
}
|
||||
|
||||
export function inferTypeForThisFromReferences(references: ReadonlyArray<Identifier>, program: Program, cancellationToken: CancellationToken) {
|
||||
if (references.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const checker = program.getTypeChecker();
|
||||
const usageContext: UsageContext = {};
|
||||
|
||||
for (const reference of references) {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
inferTypeFromContext(reference, checker, usageContext);
|
||||
}
|
||||
|
||||
return unifyFromContext(usageContext.candidateThisTypes || emptyArray, checker);
|
||||
}
|
||||
|
||||
function inferTypeFromContext(node: Expression, checker: TypeChecker, usageContext: UsageContext): void {
|
||||
while (isRightSideOfQualifiedNameOrPropertyAccess(node)) {
|
||||
node = <Expression>node.parent;
|
||||
@ -455,6 +517,13 @@ namespace ts.codefix {
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
inferTypeFromPropertyElementExpressionContext(<ElementAccessExpression>node.parent, node, checker, usageContext);
|
||||
break;
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
case SyntaxKind.ShorthandPropertyAssignment:
|
||||
inferTypeFromPropertyAssignment(<PropertyAssignment | ShorthandPropertyAssignment>node.parent, checker, usageContext);
|
||||
break;
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
inferTypeFromPropertyDeclaration(<PropertyDeclaration>node.parent, checker, usageContext);
|
||||
break;
|
||||
case SyntaxKind.VariableDeclaration: {
|
||||
const { name, initializer } = node.parent as VariableDeclaration;
|
||||
if (node === name) {
|
||||
@ -647,6 +716,21 @@ namespace ts.codefix {
|
||||
}
|
||||
}
|
||||
|
||||
function inferTypeFromPropertyAssignment(assignment: PropertyAssignment | ShorthandPropertyAssignment, checker: TypeChecker, usageContext: UsageContext) {
|
||||
const objectLiteral = isShorthandPropertyAssignment(assignment) ?
|
||||
assignment.parent :
|
||||
assignment.parent.parent;
|
||||
const nodeWithRealType = isVariableDeclaration(objectLiteral.parent) ?
|
||||
objectLiteral.parent :
|
||||
objectLiteral;
|
||||
|
||||
addCandidateThisType(usageContext, checker.getTypeAtLocation(nodeWithRealType));
|
||||
}
|
||||
|
||||
function inferTypeFromPropertyDeclaration(declaration: PropertyDeclaration, checker: TypeChecker, usageContext: UsageContext) {
|
||||
addCandidateThisType(usageContext, checker.getTypeAtLocation(declaration.parent));
|
||||
}
|
||||
|
||||
interface Priority {
|
||||
high: (t: Type) => boolean;
|
||||
low: (t: Type) => boolean;
|
||||
@ -841,6 +925,12 @@ namespace ts.codefix {
|
||||
}
|
||||
}
|
||||
|
||||
function addCandidateThisType(context: UsageContext, type: Type | undefined) {
|
||||
if (type && !(type.flags & TypeFlags.Any) && !(type.flags & TypeFlags.Never)) {
|
||||
(context.candidateThisTypes || (context.candidateThisTypes = [])).push(type);
|
||||
}
|
||||
}
|
||||
|
||||
function hasCallContext(usageContext: UsageContext | undefined): boolean {
|
||||
return !!usageContext && !!usageContext.callContexts;
|
||||
}
|
||||
|
||||
@ -222,6 +222,12 @@ namespace ts.textChanges {
|
||||
|
||||
export type TypeAnnotatable = SignatureDeclaration | VariableDeclaration | ParameterDeclaration | PropertyDeclaration | PropertySignature;
|
||||
|
||||
export type ThisTypeAnnotatable = FunctionDeclaration | FunctionExpression;
|
||||
|
||||
export function isThisTypeAnnotatable(containingFunction: FunctionLike): containingFunction is ThisTypeAnnotatable {
|
||||
return isFunctionExpression(containingFunction) || isFunctionDeclaration(containingFunction);
|
||||
}
|
||||
|
||||
export class ChangeTracker {
|
||||
private readonly changes: Change[] = [];
|
||||
private readonly newFiles: { readonly oldFile: SourceFile | undefined, readonly fileName: string, readonly statements: ReadonlyArray<Statement> }[] = [];
|
||||
@ -393,6 +399,13 @@ namespace ts.textChanges {
|
||||
this.insertNodeAt(sourceFile, endNode.end, type, { prefix: ": " });
|
||||
}
|
||||
|
||||
public tryInsertThisTypeAnnotation(sourceFile: SourceFile, node: ThisTypeAnnotatable, type: TypeNode): void {
|
||||
const start = findChildOfKind(node, SyntaxKind.OpenParenToken, sourceFile)!.getStart(sourceFile) + 1;
|
||||
const suffix = node.parameters.length ? ", " : "";
|
||||
|
||||
this.insertNodeAt(sourceFile, start, type, { prefix: "this: ", suffix });
|
||||
}
|
||||
|
||||
public insertTypeParameters(sourceFile: SourceFile, node: SignatureDeclaration, typeParameters: ReadonlyArray<TypeParameterDeclaration>): void {
|
||||
// If no `(`, is an arrow function `x => x`, so use the pos of the first parameter
|
||||
const start = (findChildOfKind(node, SyntaxKind.OpenParenToken, sourceFile) || first(node.parameters)).getStart(sourceFile);
|
||||
|
||||
@ -128,10 +128,10 @@ function foo3() {
|
||||
}
|
||||
function foo4() {
|
||||
var y = /** @class */ (function () {
|
||||
function class_1() {
|
||||
function y() {
|
||||
}
|
||||
class_1.prototype.m = function () { return x; };
|
||||
return class_1;
|
||||
y.prototype.m = function () { return x; };
|
||||
return y;
|
||||
}());
|
||||
var x;
|
||||
}
|
||||
@ -156,19 +156,19 @@ function foo7() {
|
||||
}
|
||||
function foo8() {
|
||||
var y = /** @class */ (function () {
|
||||
function class_2() {
|
||||
function class_1() {
|
||||
this.a = x;
|
||||
}
|
||||
return class_2;
|
||||
return class_1;
|
||||
}());
|
||||
var x;
|
||||
}
|
||||
function foo9() {
|
||||
var _a;
|
||||
var y = (_a = /** @class */ (function () {
|
||||
function class_3() {
|
||||
function class_2() {
|
||||
}
|
||||
return class_3;
|
||||
return class_2;
|
||||
}()),
|
||||
_a.a = x,
|
||||
_a);
|
||||
@ -187,9 +187,9 @@ function foo11() {
|
||||
function f() {
|
||||
var _a;
|
||||
var y = (_a = /** @class */ (function () {
|
||||
function class_4() {
|
||||
function class_3() {
|
||||
}
|
||||
return class_4;
|
||||
return class_3;
|
||||
}()),
|
||||
_a.a = x,
|
||||
_a);
|
||||
@ -199,10 +199,10 @@ function foo11() {
|
||||
function foo12() {
|
||||
function f() {
|
||||
var y = /** @class */ (function () {
|
||||
function class_5() {
|
||||
function class_4() {
|
||||
this.a = x;
|
||||
}
|
||||
return class_5;
|
||||
return class_4;
|
||||
}());
|
||||
}
|
||||
var x;
|
||||
|
||||
@ -9,11 +9,11 @@ let x = (new C).foo();
|
||||
|
||||
//// [classExpression4.js]
|
||||
var C = /** @class */ (function () {
|
||||
function class_1() {
|
||||
function C() {
|
||||
}
|
||||
class_1.prototype.foo = function () {
|
||||
C.prototype.foo = function () {
|
||||
return new C();
|
||||
};
|
||||
return class_1;
|
||||
return C;
|
||||
}());
|
||||
var x = (new C).foo();
|
||||
|
||||
@ -28,9 +28,9 @@ var A = /** @class */ (function () {
|
||||
return A;
|
||||
}());
|
||||
var C = /** @class */ (function (_super) {
|
||||
__extends(class_1, _super);
|
||||
function class_1() {
|
||||
__extends(C, _super);
|
||||
function C() {
|
||||
return _super !== null && _super.apply(this, arguments) || this;
|
||||
}
|
||||
return class_1;
|
||||
return C;
|
||||
}(A));
|
||||
|
||||
@ -47,11 +47,11 @@ var __extends = (this && this.__extends) || (function () {
|
||||
})();
|
||||
exports.__esModule = true;
|
||||
exports.simpleExample = /** @class */ (function () {
|
||||
function class_1() {
|
||||
function simpleExample() {
|
||||
}
|
||||
class_1.getTags = function () { };
|
||||
class_1.prototype.tags = function () { };
|
||||
return class_1;
|
||||
simpleExample.getTags = function () { };
|
||||
simpleExample.prototype.tags = function () { };
|
||||
return simpleExample;
|
||||
}());
|
||||
exports.circularReference = /** @class */ (function () {
|
||||
function C() {
|
||||
@ -70,13 +70,13 @@ var FooItem = /** @class */ (function () {
|
||||
exports.FooItem = FooItem;
|
||||
function WithTags(Base) {
|
||||
return /** @class */ (function (_super) {
|
||||
__extends(class_2, _super);
|
||||
function class_2() {
|
||||
__extends(class_1, _super);
|
||||
function class_1() {
|
||||
return _super !== null && _super.apply(this, arguments) || this;
|
||||
}
|
||||
class_2.getTags = function () { };
|
||||
class_2.prototype.tags = function () { };
|
||||
return class_2;
|
||||
class_1.getTags = function () { };
|
||||
class_1.prototype.tags = function () { };
|
||||
return class_1;
|
||||
}(Base));
|
||||
}
|
||||
exports.WithTags = WithTags;
|
||||
|
||||
@ -3,7 +3,7 @@ tests/cases/compiler/implicitAnyFromCircularInference.ts(5,5): error TS2502: 'b'
|
||||
tests/cases/compiler/implicitAnyFromCircularInference.ts(6,5): error TS2502: 'c' is referenced directly or indirectly in its own type annotation.
|
||||
tests/cases/compiler/implicitAnyFromCircularInference.ts(9,5): error TS2502: 'd' is referenced directly or indirectly in its own type annotation.
|
||||
tests/cases/compiler/implicitAnyFromCircularInference.ts(14,10): error TS7023: 'g' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
|
||||
tests/cases/compiler/implicitAnyFromCircularInference.ts(17,10): error TS7024: Function implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
|
||||
tests/cases/compiler/implicitAnyFromCircularInference.ts(17,5): error TS7023: 'f1' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
|
||||
tests/cases/compiler/implicitAnyFromCircularInference.ts(22,10): error TS7024: Function implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
|
||||
tests/cases/compiler/implicitAnyFromCircularInference.ts(25,10): error TS7023: 'h' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
|
||||
tests/cases/compiler/implicitAnyFromCircularInference.ts(27,14): error TS7023: 'foo' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
|
||||
@ -38,8 +38,8 @@ tests/cases/compiler/implicitAnyFromCircularInference.ts(45,9): error TS7023: 'x
|
||||
|
||||
// Error expected
|
||||
var f1 = function () {
|
||||
~~~~~~~~
|
||||
!!! error TS7024: Function implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
|
||||
~~
|
||||
!!! error TS7023: 'f1' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
|
||||
return f1();
|
||||
};
|
||||
|
||||
|
||||
@ -78,8 +78,8 @@ function f1() {
|
||||
var g = _newTarget;
|
||||
var h = function () { return _newTarget; };
|
||||
}
|
||||
var f2 = function _b() {
|
||||
var _newTarget = this && this instanceof _b ? this.constructor : void 0;
|
||||
var f2 = function f2() {
|
||||
var _newTarget = this && this instanceof f2 ? this.constructor : void 0;
|
||||
var i = _newTarget;
|
||||
var j = function () { return _newTarget; };
|
||||
};
|
||||
|
||||
@ -265,63 +265,63 @@ var StaticName_Anonymous = /** @class */ (function () {
|
||||
return class_1;
|
||||
}());
|
||||
var StaticNameFn_Anonymous = /** @class */ (function () {
|
||||
function class_2() {
|
||||
function StaticNameFn_Anonymous() {
|
||||
}
|
||||
class_2.name = function () { }; // error
|
||||
class_2.prototype.name = function () { }; // ok
|
||||
return class_2;
|
||||
StaticNameFn_Anonymous.name = function () { }; // error
|
||||
StaticNameFn_Anonymous.prototype.name = function () { }; // ok
|
||||
return StaticNameFn_Anonymous;
|
||||
}());
|
||||
// length
|
||||
var StaticLength_Anonymous = /** @class */ (function () {
|
||||
function class_2() {
|
||||
}
|
||||
return class_2;
|
||||
}());
|
||||
var StaticLengthFn_Anonymous = /** @class */ (function () {
|
||||
function StaticLengthFn_Anonymous() {
|
||||
}
|
||||
StaticLengthFn_Anonymous.length = function () { }; // error
|
||||
StaticLengthFn_Anonymous.prototype.length = function () { }; // ok
|
||||
return StaticLengthFn_Anonymous;
|
||||
}());
|
||||
// prototype
|
||||
var StaticPrototype_Anonymous = /** @class */ (function () {
|
||||
function class_3() {
|
||||
}
|
||||
return class_3;
|
||||
}());
|
||||
var StaticLengthFn_Anonymous = /** @class */ (function () {
|
||||
var StaticPrototypeFn_Anonymous = /** @class */ (function () {
|
||||
function StaticPrototypeFn_Anonymous() {
|
||||
}
|
||||
StaticPrototypeFn_Anonymous.prototype = function () { }; // error
|
||||
StaticPrototypeFn_Anonymous.prototype.prototype = function () { }; // ok
|
||||
return StaticPrototypeFn_Anonymous;
|
||||
}());
|
||||
// caller
|
||||
var StaticCaller_Anonymous = /** @class */ (function () {
|
||||
function class_4() {
|
||||
}
|
||||
class_4.length = function () { }; // error
|
||||
class_4.prototype.length = function () { }; // ok
|
||||
return class_4;
|
||||
}());
|
||||
// prototype
|
||||
var StaticPrototype_Anonymous = /** @class */ (function () {
|
||||
var StaticCallerFn_Anonymous = /** @class */ (function () {
|
||||
function StaticCallerFn_Anonymous() {
|
||||
}
|
||||
StaticCallerFn_Anonymous.caller = function () { }; // error
|
||||
StaticCallerFn_Anonymous.prototype.caller = function () { }; // ok
|
||||
return StaticCallerFn_Anonymous;
|
||||
}());
|
||||
// arguments
|
||||
var StaticArguments_Anonymous = /** @class */ (function () {
|
||||
function class_5() {
|
||||
}
|
||||
return class_5;
|
||||
}());
|
||||
var StaticPrototypeFn_Anonymous = /** @class */ (function () {
|
||||
function class_6() {
|
||||
}
|
||||
class_6.prototype = function () { }; // error
|
||||
class_6.prototype.prototype = function () { }; // ok
|
||||
return class_6;
|
||||
}());
|
||||
// caller
|
||||
var StaticCaller_Anonymous = /** @class */ (function () {
|
||||
function class_7() {
|
||||
}
|
||||
return class_7;
|
||||
}());
|
||||
var StaticCallerFn_Anonymous = /** @class */ (function () {
|
||||
function class_8() {
|
||||
}
|
||||
class_8.caller = function () { }; // error
|
||||
class_8.prototype.caller = function () { }; // ok
|
||||
return class_8;
|
||||
}());
|
||||
// arguments
|
||||
var StaticArguments_Anonymous = /** @class */ (function () {
|
||||
function class_9() {
|
||||
}
|
||||
return class_9;
|
||||
}());
|
||||
var StaticArgumentsFn_Anonymous = /** @class */ (function () {
|
||||
function class_10() {
|
||||
function StaticArgumentsFn_Anonymous() {
|
||||
}
|
||||
class_10.arguments = function () { }; // error
|
||||
class_10.prototype.arguments = function () { }; // ok
|
||||
return class_10;
|
||||
StaticArgumentsFn_Anonymous.arguments = function () { }; // error
|
||||
StaticArgumentsFn_Anonymous.prototype.arguments = function () { }; // ok
|
||||
return StaticArgumentsFn_Anonymous;
|
||||
}());
|
||||
// === Static properties on default exported classes ===
|
||||
// name
|
||||
|
||||
@ -45,11 +45,11 @@ var B = /** @class */ (function (_super) {
|
||||
function B() {
|
||||
var _this = this;
|
||||
var D = /** @class */ (function (_super) {
|
||||
__extends(class_1, _super);
|
||||
function class_1() {
|
||||
__extends(D, _super);
|
||||
function D() {
|
||||
return _super.call(this) || this;
|
||||
}
|
||||
return class_1;
|
||||
return D;
|
||||
}(C));
|
||||
return _this;
|
||||
}
|
||||
|
||||
@ -0,0 +1,19 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @noImplicitThis: true
|
||||
//// function returnThisMember([| |]) {
|
||||
//// return this.member;
|
||||
//// }
|
||||
////
|
||||
//// const container: any = {
|
||||
//// member: "sample",
|
||||
//// returnThisMember: returnThisMember,
|
||||
//// };
|
||||
////
|
||||
//// container.returnThisMember();
|
||||
|
||||
verify.codeFix({
|
||||
description: "Infer 'this' type of 'returnThisMember' from usage",
|
||||
index: 0,
|
||||
newRangeContent: "this: any ",
|
||||
});
|
||||
@ -0,0 +1,22 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @noImplicitThis: true
|
||||
//// const returnThisMember = function ([| |]) {
|
||||
//// return this.member;
|
||||
//// }
|
||||
////
|
||||
//// interface Container {
|
||||
//// member: string;
|
||||
//// returnThisMember(): string;
|
||||
//// }
|
||||
////
|
||||
//// const container: Container = {
|
||||
//// member: "sample",
|
||||
//// returnThisMember: returnThisMember,
|
||||
//// };
|
||||
|
||||
verify.codeFix({
|
||||
description: "Infer 'this' type of 'returnThisMember' from usage",
|
||||
index: 0,
|
||||
newRangeContent: "this: Container ",
|
||||
});
|
||||
@ -0,0 +1,25 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @noImplicitThis: true
|
||||
////function returnThisMember([| |]) {
|
||||
//// return this.member;
|
||||
//// }
|
||||
////
|
||||
//// interface Container {
|
||||
//// member: string;
|
||||
//// returnThisMember(): string;
|
||||
//// }
|
||||
////
|
||||
//// let container;
|
||||
//// container = {
|
||||
//// member: "sample",
|
||||
//// returnThisMember: returnThisMember,
|
||||
//// };
|
||||
////
|
||||
//// container.returnThisMember();
|
||||
|
||||
verify.codeFix({
|
||||
description: "Infer 'this' type of 'returnThisMember' from usage",
|
||||
index: 0,
|
||||
newRangeContent: "this: { member: string; returnThisMember: () => any; } ",
|
||||
});
|
||||
@ -0,0 +1,39 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @noImplicitThis: true
|
||||
|
||||
// @Filename: /consumesType.js
|
||||
/////**
|
||||
//// * @returns {string}
|
||||
//// */
|
||||
////function [|returnThisMember|]() {
|
||||
//// return this.member;
|
||||
////}
|
||||
////
|
||||
////class Container {
|
||||
//// member = "sample";
|
||||
//// returnThisMember = returnThisMember;
|
||||
////};
|
||||
////
|
||||
////container.returnThisMember();
|
||||
|
||||
verify.codeFix({
|
||||
description: "Infer 'this' type of 'returnThisMember' from usage",
|
||||
index: 0,
|
||||
newFileContent: `/**
|
||||
* @returns {string}
|
||||
* @this {Container}
|
||||
*/
|
||||
function returnThisMember() {
|
||||
return this.member;
|
||||
}
|
||||
|
||||
class Container {
|
||||
member = "sample";
|
||||
returnThisMember = returnThisMember;
|
||||
};
|
||||
|
||||
container.returnThisMember();`
|
||||
});
|
||||
@ -0,0 +1,35 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @noImplicitThis: true
|
||||
|
||||
// @Filename: /consumesType.js
|
||||
////function [|returnThisMember|]() {
|
||||
//// return this.member;
|
||||
////}
|
||||
////
|
||||
////class Container {
|
||||
//// member = "sample";
|
||||
//// returnThisMember = returnThisMember;
|
||||
////};
|
||||
////
|
||||
////container.returnThisMember();
|
||||
|
||||
verify.codeFix({
|
||||
description: "Infer 'this' type of 'returnThisMember' from usage",
|
||||
index: 0,
|
||||
newFileContent: `/**
|
||||
* @this {Container}
|
||||
*/
|
||||
function returnThisMember() {
|
||||
return this.member;
|
||||
}
|
||||
|
||||
class Container {
|
||||
member = "sample";
|
||||
returnThisMember = returnThisMember;
|
||||
};
|
||||
|
||||
container.returnThisMember();`
|
||||
});
|
||||
@ -0,0 +1,47 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @noImplicitThis: true
|
||||
|
||||
// @Filename: /consumesType.js
|
||||
////function [|returnThisMember|]() {
|
||||
//// return this.member;
|
||||
////}
|
||||
////
|
||||
/////**
|
||||
//// * @type {import("/providesType").Container}
|
||||
//// */
|
||||
////const container = {
|
||||
//// member: "sample",
|
||||
//// returnThisMember: returnThisMember,
|
||||
////};
|
||||
////
|
||||
////container.returnThisMember();
|
||||
|
||||
// @Filename: /providesType.ts
|
||||
////interface Container {
|
||||
//// member: string;
|
||||
//// returnThisMember(): string;
|
||||
////}
|
||||
|
||||
verify.codeFix({
|
||||
description: "Infer 'this' type of 'returnThisMember' from usage",
|
||||
index: 0,
|
||||
newFileContent: `/**
|
||||
* @this {any}
|
||||
*/
|
||||
function returnThisMember() {
|
||||
return this.member;
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {import("/providesType").Container}
|
||||
*/
|
||||
const container = {
|
||||
member: "sample",
|
||||
returnThisMember: returnThisMember,
|
||||
};
|
||||
|
||||
container.returnThisMember();`
|
||||
});
|
||||
@ -0,0 +1,35 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @noImplicitThis: true
|
||||
|
||||
// @Filename: /consumesType.js
|
||||
////function [|returnThisMember|]() {
|
||||
//// return this.member;
|
||||
////}
|
||||
////
|
||||
////const container = {
|
||||
//// member: "sample",
|
||||
//// returnThisMember: returnThisMember,
|
||||
////};
|
||||
////
|
||||
////container.returnThisMember();
|
||||
|
||||
verify.codeFix({
|
||||
description: "Infer 'this' type of 'returnThisMember' from usage",
|
||||
index: 0,
|
||||
newFileContent: `/**
|
||||
* @this {{ member: string; returnThisMember: () => any; }}
|
||||
*/
|
||||
function returnThisMember() {
|
||||
return this.member;
|
||||
}
|
||||
|
||||
const container = {
|
||||
member: "sample",
|
||||
returnThisMember: returnThisMember,
|
||||
};
|
||||
|
||||
container.returnThisMember();`
|
||||
});
|
||||
@ -0,0 +1,17 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @noImplicitThis: true
|
||||
////function returnThisMember([| |]) {
|
||||
//// return this.member;
|
||||
//// }
|
||||
////
|
||||
//// const container = {
|
||||
//// member: "sample",
|
||||
//// returnThisMember: returnThisMember,
|
||||
//// };
|
||||
|
||||
verify.codeFix({
|
||||
description: "Infer 'this' type of 'returnThisMember' from usage",
|
||||
index: 0,
|
||||
newRangeContent: "this: { member: string; returnThisMember: () => any; } ",
|
||||
});
|
||||
@ -0,0 +1,12 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @noImplicitThis: true
|
||||
////function returnThisMember([| |]) {
|
||||
//// return this.member;
|
||||
//// }
|
||||
|
||||
verify.codeFix({
|
||||
description: "Infer 'this' type of 'returnThisMember' from usage",
|
||||
index: 0,
|
||||
newRangeContent: "this: any ",
|
||||
});
|
||||
@ -0,0 +1,20 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @noImplicitThis: true
|
||||
////function returnThisMember([| |]) {
|
||||
//// return this.member;
|
||||
//// }
|
||||
////
|
||||
//// interface Container {
|
||||
//// member: string;
|
||||
//// returnThisMember(): string;
|
||||
//// }
|
||||
////
|
||||
//// const container: Container = {
|
||||
//// member: "sample",
|
||||
//// returnThisMember: returnThisMember,
|
||||
//// };
|
||||
////
|
||||
//// container.returnThisMember();
|
||||
|
||||
verify.rangeAfterCodeFix("this: Container");
|
||||
@ -0,0 +1,20 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @noImplicitThis: true
|
||||
////function returnThisMember([| |]suffix: string) {
|
||||
//// return this.member + suffix;
|
||||
//// }
|
||||
////
|
||||
//// interface Container {
|
||||
//// member: string;
|
||||
//// returnThisMember(suffix: string): string;
|
||||
//// }
|
||||
////
|
||||
//// const container: Container = {
|
||||
//// member: "sample",
|
||||
//// returnThisMember: returnThisMember,
|
||||
//// };
|
||||
////
|
||||
//// container.returnThisMember("");
|
||||
|
||||
verify.rangeAfterCodeFix("this: Container, ");
|
||||
@ -0,0 +1,20 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @noImplicitThis: true
|
||||
////function returnThisMember([| |]) {
|
||||
//// return this.member;
|
||||
//// }
|
||||
////
|
||||
//// interface Container {
|
||||
//// member: string;
|
||||
//// returnThisMember(): string;
|
||||
//// }
|
||||
////
|
||||
//// const container: Container = {
|
||||
//// member: "sample",
|
||||
//// returnThisMember,
|
||||
//// };
|
||||
////
|
||||
//// container.returnThisMember();
|
||||
|
||||
verify.rangeAfterCodeFix("this: Container");
|
||||
@ -0,0 +1,20 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @noImplicitThis: true
|
||||
////function returnThisMember([| |]suffix: string) {
|
||||
//// return this.member + suffix;
|
||||
//// }
|
||||
////
|
||||
//// interface Container {
|
||||
//// member: string;
|
||||
//// returnThisMember(suffix: string): string;
|
||||
//// }
|
||||
////
|
||||
//// const container: Container = {
|
||||
//// member: "sample",
|
||||
//// returnThisMember,
|
||||
//// };
|
||||
////
|
||||
//// container.returnThisMember("");
|
||||
|
||||
verify.rangeAfterCodeFix("this: Container, ");
|
||||
Loading…
x
Reference in New Issue
Block a user