-
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
Literal types and Arrray.prototype.includes typings #32201
Comments
Related to or duplicate of #26255 Also relevant Stack Overflow answer |
Thanks for the reference, @jcalz. I'm not surprised that this has come up before. I'd like to think this issue isn't quite a duplicate, in that it offers a proposal for fixing the problem in the standard lib without waiting for lower-bounded type parameters to be implemented in TS. That said, I'd like to update my proposal to be more general, following your answer on Stack Overflow and hack mentioned at the top of #14520. So, that would be: includes<U extends (T extends U ? unknown : never)>(searchElement: U, fromIndex?: number): boolean; or: includes<T extends U, U>(searchElement: U, fromIndex?: number): boolean; @RyanCavanaugh How do you feel about updating the standard lib to use one of these known workarounds while we're waiting for upper bounded generics? Personally, I don't see any harm, especially if the first workaround given above (from @jcalz's Stack Overflow answer) is used, as the final signature would likely be backwards compatible with that workaround, I think (since both would introduce one type parameter that means conceptually the same thing). |
This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes. |
I have been experimenting with this implementation, which seems to resolve the issue for me and makes no casts, ensuring that Typescript can keep doing its good job of widening as much as necessary and narrowing as much as possible without me having to claim I know better than the compiler. I'm posting it here since it doesn't seem to have been mentioned anywhere. function constArrayIncludes<Item extends any, Arr extends readonly Item[]>(
arr: Arr,
item: Item
) {
return arr.includes(item);
} It ensures I can use e.g. ... const operatorNames = ["add", "subtract", "divide", "multiply"] as const; ...to define valid literals available to javascript, then write typeguards like... function operatorGuard(tile:Tile) : tile is Operator{
return constArrayIncludes(operatorNames, tile);
} There also seems to be a useful Generic implementation using the same strategy... function genericGuard<Item extends any, Arr extends readonly Item[]>(arr:Arr, item:Item): item is typeof arr[number]{
return constArrayIncludes(arr, item);
} The full experiment, including a Generic typeguard for cases of const arrays is here in this playground As shown in this screenshot it also correctly reports a failure against a typical problem case that @RyanCavanaugh mentioned in #26255 |
Search Terms
includes (in the label "Domain: lib.d.ts")
Suggestion
Change the typing for
A.p.includes
in lib.d.ts. See below.Use Cases/Examples
I often use
Array.prototype.includes
to validate at runtime that a user-provided value is in some list of legal values:The above works great. However, the problem comes when I want to use literal types for my legal values. In my code, I want to do that so I can make sure I define a "handler" for every legal value:
The problem is that, with the literal types, the
includes
call now gives a type error:I think a more natural/appropriate behavior for type signature of
includes
would be for the literal types to be widened. But, since I don't think there's a way to write that in the type signature directly, I'd propose something similar manually by changing the definition from:to:
Checklist
My suggestion meets these guidelines:
The text was updated successfully, but these errors were encountered: