-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
fix(eslint-plugin): [prefer-function-type] handle this
type
#1783
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Thanks for the PR, @anikethsaha! typescript-eslint is a 100% community driven project, and we are incredibly grateful that you are contributing to that community. The core maintainers work on this in their personal time, so please understand that it may not be possible for them to review your work immediately. Thanks again! 🙏 Please, if you or your company is finding typescript-eslint valuable, help us sustain the project by sponsoring it transparently on https://opencollective.com/typescript-eslint. As a thank you, your profile/company logo will be added to our main README which receives thousands of unique visitors per day. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about cases like
interface Interface {(): this | string}
interface Interface {(): Array<this>}
interface Interface {(arg: this): void}
interface Interface {(arg: this | string): void}
interface Interface {(arg: Array<this>): void}
In addition to the other comment, this PR should handle all cases where a callable interface uses this this
type.
interface Interface {(): this | string} // valid
interface Interface {(): Array<this>} // not sure, I will add a test for this to check
interface Interface {(arg: this): void} // it will be invalid !
interface Interface {(arg: this | string): void} // it will be invalid !
interface Interface {(arg: Array<this>): void} // it will be invalid !
Should I add support for parameters as well ? or they should be kept as invalid ? |
With this fix, we will want to update the fixer so it does not output semantically invalid code. But in this case it's pretty clear-cut: a |
so, what I understood, we have to disable the fixer for |
There are essentially two options here. When the rule detects an interface that use the
|
ok, that make sense, just one query though,
|
whenever interface Interface1a {(): this}
type Interface1b = {(): Interface1b}
interface Interface2a {(): this | string}
type Interface2b = {(): Interface2b | string}
interface Interface3a {(): Array<this>}
type Interface3b = {(): Array<Interface3b>}
interface Interface4a {(arg: this): void}
type Interface4b = {(arg: Interface4b): void}
interface Interface5a {(arg: this | string): void}
type Interface5b = {(arg: Interface5b | string): void}
interface Interface6a {(arg: Array<this>): void}
type Interface6b = {(arg: Array<Interface6b>): void} |
ok cool, I will change it |
this
type
output: `type Interface = () => Interface`, | ||
}, | ||
{ | ||
code: 'interface Interface {(): Object<this>}', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bradzacher this ( generic types ) will fail as the latest commit is still WIP.
@bradzacher the latest commit is still WIP As per the review I made changes in the fixer.
|
if (node.type === AST_NODE_TYPES.TSThisType) { | ||
return node.range; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are few overlapping issue while comparing which is why I think the CI is failing, should I turn off the rule there ?
This is failing the typecheck because it can never be true.
Your argument is of type TSESTree.TypeAnnotation
, which is a container node.
See my other comment for a suggestion of how to structure the function.
function getReturnType( | ||
node: TSESTree.TSTypeAnnotation, | ||
): Array<number> | null { | ||
if (!possibleReturnThisTypeHolders.has(node.type)) { | ||
return null; | ||
} | ||
|
||
if (node.type === AST_NODE_TYPES.TSThisType) { | ||
return node.range; | ||
} | ||
|
||
if (node.type === AST_NODE_TYPES.TSTypeAnnotation) { | ||
if (node.typeAnnotation.type === AST_NODE_TYPES.TSThisType) { | ||
return node.typeAnnotation.range; | ||
} | ||
} | ||
|
||
if (node.type === AST_NODE_TYPES.TSFunctionType) { | ||
return getReturnType(node?.returnType); | ||
} | ||
|
||
return null; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
function getReturnType( | |
node: TSESTree.TSTypeAnnotation, | |
): Array<number> | null { | |
if (!possibleReturnThisTypeHolders.has(node.type)) { | |
return null; | |
} | |
if (node.type === AST_NODE_TYPES.TSThisType) { | |
return node.range; | |
} | |
if (node.type === AST_NODE_TYPES.TSTypeAnnotation) { | |
if (node.typeAnnotation.type === AST_NODE_TYPES.TSThisType) { | |
return node.typeAnnotation.range; | |
} | |
} | |
if (node.type === AST_NODE_TYPES.TSFunctionType) { | |
return getReturnType(node?.returnType); | |
} | |
return null; | |
} | |
function getReturnType( | |
node: TSESTree.TSTypeAnnotation, | |
): Array<number> | null { | |
if (node.typeAnnotation.type === AST_NODE_TYPES.TSThisType) { | |
return node.range; | |
} | |
if (node.typeAnnotation.type === AST_NODE_TYPES.TSFunctionType) { | |
return getReturnType(node?.returnType); | |
} | |
// etc | |
return null; | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried this
function getReturnType(
node: TSESTree.TSTypeAnnotation,
): Array<number> | null {
if (!possibleReturnThisTypeHolders.has(node.type)) {
return null;
}
if (node.typeAnnotation.type === AST_NODE_TYPES.TSThisType) {
return node.range;
}
if (node.typeAnnotation.type === AST_NODE_TYPES.TSTypeAnnotation) { // <--- type error
if (node.typeAnnotation.type === AST_NODE_TYPES.TSThisType) { // <--- type error
return node.typeAnnotation.range;
}
}
if (node.typeAnnotation.type === AST_NODE_TYPES.TSFunctionType) {
return getReturnType(node?.returnType);
}
return null;
}
Still no luck, even tests are failing cause of this !
Okay. So looking at this, it's going to be a bit of a pain to recurse through all of the various permutations of valid positions for the A better way to do this would be something like the following rough code. let tsThisTypes: TSESTree.TSThisType[] | null;
{
'TSInterfaceDeclaration:enter'(): void {
tsThisTypes = [];
},
'TSInterfaceDeclaration:exit'(node: TSESTree.TSInterfaceDeclaration): void {
if (!hasOneSupertype(node) && node.body.body.length === 1) {
checkMember(node.body.body[0], node);
}
tsThisTypes = null;
},
'TSTypeLiteral[members.length = 1]:enter'(): void {
tsThisTypes = [];
},
'TSTypeLiteral[members.length = 1]:exit'(node: TSESTree.TSTypeLiteral): void {
checkMember(node.members[0], node);
tsThisTypes = null;
},
TSThisType(node): void {
tsThisTypes?.push(node);
},
};
// then in the fixer for interface
for (const thisType of (tsThisTypes ?? [])) {
fixer.replaceText(thisType, interfaceName);
}
// in the reporter for TSTypeLiteral
if (tsThisTypes && tsThisTypes.length > 0) {
// cannot handle this types because we don't know the name of the type literal
// so we can't generate a recursive type
return;
} |
@bradzacher I am sorry as I couldn't able to complete this PR. I may look at this in the future if no one is taking. Thanks |
fixes #1756
this
for interface declarations