Skip to content
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

"no-misused-generics" warns about code that seems correct? #24

Open
grumd opened this issue Oct 27, 2020 · 5 comments
Open

"no-misused-generics" warns about code that seems correct? #24

grumd opened this issue Oct 27, 2020 · 5 comments
Labels
bug Something isn't working

Comments

@grumd
Copy link

grumd commented Oct 27, 2020

I'm not sure if there's a bug indeed or if I'm just wrong here.

Code:

interface Args<Foo> {
  foo: Foo;
  fooKey: keyof Foo;
}

interface MyFunction {
  <Foo>(args: Args<Foo>): any;
/* ^^^
   Type parameter 'Foo' is not used to enforce a constraint between types and can be replaced with 'unknown'
   etc/no-misused-generics
*/
}

const func: MyFunction = (args) => args.foo[args.fooKey];

func({ foo: { bar: 'bar' }, fooKey: 'bar' }); // No errors
func({ foo: { bar: 'bar' }, fooKey: 'qwerty' }); // Type '"qwerty"' is not assignable to type '"bar"'

Explanation:

Foo is used to enforce a constraint between foo: Foo and fooKey: keyof Foo.
You can see how the constraint allows for type-safety in the last two lines of my example.
I can only pass keys of foo in the fooKey parameter.

But no-misused-generics thinks that is redundant. When I replace <Foo>(args: Args<Foo>): any; with (args: Args<any>): any; or (args: Args<unknown>): any; my code stops working as intended.

Possible fix:

Ignore this rule when a type parameter is used as a nested type parameter in another generic type. If somewhere down the line this type is indeed not used to enforce a constraint, then we'll see this error down the line.

@cartant
Copy link
Owner

cartant commented Oct 27, 2020

This is a port of a Wotan rule - the link is in the docs if you want to see if there are any similar issue in its repo.

I can have more of a think about this tomorrow. I'm curious, though: does it still effect a failure if the Args type is inlined? E.g. args: { foo: Foo; fooKey: keyof Foo; }

@grumd
Copy link
Author

grumd commented Oct 27, 2020

There are zero errors when Args is inlined like this:

interface MyFunction {
  <Foo>(args: { foo: Foo; fooKey: keyof Foo }): any;
}

Yep, I looked through Wotan repository, found this which seemed similar: fimbullinter/wotan#663
They're saying they can't fix this, but I find my proposal here pretty feasible.
I'm not using Wotan though, that's why I placed an issue here.

@cartant
Copy link
Owner

cartant commented Oct 27, 2020

I'm not using Wotan though, that's why I placed an issue here.

Yeah, that's fine. I was just wondering whether there is a fundamental problem with the rule.

There are zero errors when Args is inlined

AFAICT, that means the rule could also fail if the type parameter is placed on the interface and not on the signature.

The Wotan issue looks like the issue that Dan opened in this repo. This is a little different. There might be a way to make this work. I'll have a think about it.

@cartant cartant added the bug Something isn't working label Oct 27, 2020
@cartant
Copy link
Owner

cartant commented Oct 27, 2020

For the moment, I've removed no-misused-generic from the recommended rules. IMO, it ought to be possible to fix this issue and to address Dan's (by adding an option to allow for return-type-based inference).

@grumd
Copy link
Author

grumd commented Oct 30, 2020

I'm still standing by my idea of adding an option to ignore this rule when a non-inferred T is passed as a type parameter into some other generic type. But it's still up to you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants