-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Enable extraction of type parameters. #49112
Comments
I donβt understand what |
Well I made my case already why it makes sense. Also you are not asking what the value is. You are just assigning a label to it. |
The βvalueβ in this case is the type assigned to |
@lillallol Pretty sure this isn't possible, at least not as you're suggesting. The big issue is that What would it mean if someone wrote code like: // MyModule.ts
import { IChunkTypeParameter } from "lib";
// What type is x here?
const x: IChunkTypeParameter = "is this allowed?"; Generally, I'd recommend avoiding the "type alias for a generic function" pattern in favor of generic functions, where possible. Instead of code like: const chunk: IChunk = (array, length) => {
const toReturn: Array<typeof array> = [];
return toReturn;
} I'd usually recommend: function chunk<T>(array: T[], length: number) => {
const toReturn: T[][] = [];
return toReturn;
} There's some cases where extracting the whole type of the function out into its own type can be useful, but I think they're somewhat rare. (I used TS syntax throughout, because I'm way more comfortable with it - I don't think any of this problem is really unique to JS + JSDoc types syntax) |
Yes it makes sense only inside a chunk annotated function.
Of course this is not allowed since it is not possible to know whether type IChunkToReturn = IChunkTypeParameter[][];
Why?
I do not understand this sentence.
I already answered that.
I already did. Provide extra cases like @Retsam and I would gladly answer. |
I think this makes this suggestion pretty much a non-starter. I'm pretty sure there aren't any examples of a type that works like this: having the type alias's type be implicitly contextual to where it's used is rather strange, so yes, I'd say it's probably close to "impossible". Certainly, I suspect it would take a far more compelling reason than "it's slightly more convenient in this fairly niche case".
Mostly I avoid annotating whole function types because it's a lot more convenient, less repetitive: const identity: <T>(x: T) => T = (x) => x;
// a lot more 'noisy' than the equivalent:
const identity = <T>(x: T) => x; But also in part because of stuff like this. You just don't need something like |
This can happen only when you write both concretions and types in
Look I can understand that using TypeScript without the need to compile is something that is not widely adopted, and maybe TypeScript maintainers will not give high priority for such features. I would like to have a clear answer from the TypeScript maintainers though, on whether the feature is intrinsically impossible due to TypeScript design. |
@lillallol You can still write the equivalent code in JS files, though: /**
* @template T
* @param {T[]} items
* @param {number} length
*/
function chunk(items, length) {
/** @type {T[][]} */
const toReturn = [];
return toReturn;
} |
Yes you are right. Here are my objections though:
I do consider the benefits that occur from these two reasons (especially the second one) enough for this feature to be adopted. |
This is conceptually unmoored in a number of ways. This isn't even about TypeScript; AFAIK any language with type parameters does not enable this sort of operation.
In cases where this would make sense you can use something like |
I explained how it is not meaningless based on the initial example I provided but also the conversation I had in the previous comments. Is that not enough? Also the type parameter is virtually outside a generic context. All I am asking is that the context that enables us to use const chunk = <T>(array : T[],length : number) => {
const toReturn : T[][] = [];
// calculation of toReturn omitted for brevity
return toReturn;
} to be enabled via something like
How does that relate to my feature request? Care to elaborate with an example? Are you referring to more involved cases?
Yes in my projects, for the initial example, I did use infer array element inside a JSDoc type tag. Then I realized I can just use |
This example keeps getting posted, but you haven't yet given any examples of how |
I get that you don't like any of the existing solutions, but the proposed idea here is not a viable solution because it would introduce a type that's completely meaningless outside of the context where the type should have been declared in the first place. |
So we are dealing with a design limitation?
Good question. Here is the answer:
If you try to adhere to these two points then you will realize that you need a feature like |
By the way I would like to mention that for the example I have provided, there is a solution like this:
export type IChunk = <T>(
array : T[],
length : number,
toReturn? : T[][],
) => T[][];
/**@type {import("./privateApi").IChunk}*/
export const chunk = (array,length,toReturn = []) => {
/* some code that calculates `toReturn` */
return toReturn;
} Although that might not feel hacky for the context example, I have faced other examples where the extra parameter serves only the function definition and it is not supposed in any case to be provided a value by the consumer of the function. This can be solved by defining wrapper functions that hide the parameters that are not supposed to be exposed. For the example I have provided this is done like this:
export type IChunkPrivate = <T>(
array : T[],
length : number,
toReturn? : T[][],
) => T[][];
export type IChunk = <T>(
array : T[],
length : number,
) => T[][];
/**@type {import("./privateApi").IChunkPrivate}*/
export const chunkPrivate = (array,length,toReturn = []) => {
/* some code that calculates `toReturn` */
return toReturn;
};
/**@type {import("./privateApi").IChunk}*/
export const chunk = (...parameters) => chunkPrivate(...parameters); A feature like |
No. We "could" do this (indeed, bugs have existed where you could accidently make this happen), but we're not going to, because it doesn't make any sense to allow a type parameter to escape its enclosing context, because outside of that context, there's no meaning to give those types. |
I was looking for something similar today, but to extract the part after import lib from 'lib'
export function myLib<LibTypeParam extends TypeParameters<typeof lib>[0]>(
...libParameters: Parameters<typeof lib>
) {
/* ... do something custom ... */
return lib<LibTypeParam>(...libParameters);
} |
WorkaroundThe workaround that we found for replicating the wrapper pattern above was to use casting, although I'm not sure if this works in every case: import lib from 'lib'
export (function myLib(
...libParameters: Parameters<typeof lib>
) {
/* ... do something custom ... */
return lib(...libParameters);
}) as typeof lib |
@RyanCavanaugh By the way for the following code snippet: const chunk = <T>(array : T[],length : number):T[][] => {
const toReturn = [];
// calculation of toReturn omitted for brevity
return toReturn;
} can a static type system (not just TypeScript) be made to infer the type of |
Suggestion
π Search Terms
allowJs, checkJs, no compile, JSDoc type import, type parameter extraction
β Viability Checklist
My suggestion meets these guidelines:
β Suggestion
Enable extraction of type parameters with a utility function called
TypeParameters
../privateApi.ts
π Motivating Example and π» Use Cases
./chunk.js
Question
I would like to know whether the design of TypeScript is such, that
TypeParameters
is possible.The text was updated successfully, but these errors were encountered: