Skip to content

Generic parameters are sometimes not optional when their type resolves to void #43820

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

Closed
bave8672 opened this issue Apr 25, 2021 · 2 comments
Closed
Labels
Duplicate An existing issue was already created

Comments

@bave8672
Copy link

Bug Report

🔎 Search Terms

Generic function method static constructor void optional required

🕗 Version & Regression Information

  • Tested up to 4.3.0-beta
  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about generics and function signatures.

⏯ Playground Link

https://www.typescriptlang.org/play?ts=4.2.3#code/PQKhAIGUBcEMDsAmsBOjwDcD2BLdAjAUwAtYMcsVwRgAoAMwFd4BjaC+cegHgBUA+ABQAPAFyZciAJTgA3gF8Gg5okL0c8QtIDc4YMHAB5ANJKpu-UdO1QEAGqTwRUuSyMqAd2KFOjAM4aAObgAAaEwtA+iH4h4H4AnvBwwtR0TKzsWJyBfEJi4Lzg4ZFIfuAI8eAA-BJ44OLYeDIKtIHKSGoaWjKWJq2C5noGAKLCAA6EbFrgAIzlKIGMALY+0H4ANE6M0OCBWDsADAB0rdx+0ChBQoOWoxNT6HOoiytJG1s7e4cnOfDLRChrhYRuNJpFHvMXqt3vhtrt9uBjrQbGBwABhAA2sD8ZXCsCWYwxhHAAFpwPB9sToKQditqVhouUxhNUOBoFgnCQyMTsUVQQ9UrQWFiceAAIK5OS0cAy8AsLLnFCMNiUETiQrFKJlP5LAHVWroBqSZqKWVxODsFhcXJqgp8kqMnV6mqNQ0Gk3S2X0W0aiJa8n-QhUF2OI1NOSKRSaDzis4XK4DYHgYYoFCUcR3MHTJ4LZbQzawz4IpFio48RUJm4jVPp5P88GzSF5t4FuFfRG0aOxivwQJCFSdTTSMuJoZWWhAA

💻 Code

/** Standard void behavior */
function f<T>(x: void) {}
f(undefined); // OK
f(); // OK

/** Void behavior when using `extends` syntax */
function g<T>(x: T extends any ? void : void) {}
g(undefined) // OK
g(); // Expected 1 arguments, but got 0.
g<string>(); // Expected 1 arguments, but got 0.
g<number>(); // Expected 1 arguments, but got 0.

/** Class example - note that methods appear to behave as expected */
class A<T> {
    constructor(x: T extends number ? void : void) {}
    static f<T>(x: T extends number ? void : void) {}
    f(x: T extends number ? void : void) {}
}
new A<string>(); // Error: Expected 1 arguments, but got 0.
A.f<string>(); // Error: Expected 1 arguments, but got 0
new A<string>(undefined).f(); // OK

🙁 Actual behavior

For functions, static methods, constructors, that use the extends syntax, typescript treats void arguments as required.

🙂 Expected behavior

Arguments that are known to be void are always treated as optional.

@jcalz
Copy link
Contributor

jcalz commented Apr 26, 2021

Duplicate of #29131?

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Apr 26, 2021
@typescript-bot
Copy link
Collaborator

This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

Offroaders123 added a commit to Offroaders123/NBTify that referenced this issue Jun 8, 2023
I wish this was working, it would be really cool! It extends the similar behavior that the `NBTData` data does, where it attaches the format options types as a generic on the `NBTData` type itself. This would be neat to define the shape of the `NBTData` object fully, including it's content, and it's format options.

While writing that last part, I realized a better way to handle this, and may be generics on the `NBTData` object aren't the way to go. Since it's only the types that have to stay static, maybe it makes more sense to manage these from a level above the `NBTData` object. I would have liked to be able to constrain the values you pass into the `NBTData` object, by using generic constraints, but it seems like this prevents you from allowing the parameter to be optional.

I think I found some options to describe the error, I think they are related to the issue I'm having. The type issues are only occurring when the options parameter is applied with a default value, or set to anything other than the type of itself. Even with type casting to either `FormatOptions` or `U`, it won't let you assign anything to the parameter.

https://stackoverflow.com/questions/56505560/how-to-fix-ts2322-could-be-instantiated-with-a-different-subtype-of-constraint
microsoft/TypeScript#50027
https://www.reddit.com/r/typescript/comments/rncy44/implementing_function_types_with_a_generic/
https://news.ycombinator.com/item?id=30247357
https://stackoverflow.com/questions/67397978/ts2322-generic-not-propagated-correctly
microsoft/TypeScript#43820

After discussing that, I think that's probably the way to go. Maybe the `NBTData` object shouldn't be where things are dictated, hmm. It seems to work really nice with the `NBT.read()` and `NBT.write()` functions though, and I wish I didn't have to lose that functionality.

The next stage I may try for this is to make a generic for each option parameter. I don't really like the idea of that though. Let's see what happens. This is so close! I realized the `const U ...` const declaration for the generic works great here too, which makes the `NBTData` properties reflect the options you pass into the options object, with exact values. So passing in `"Level"` for the name option will reflect `"Level"`, rather than only `string`, which is what happens without using `const U`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

4 participants