microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
101.21k stars 12.51k forks source link

Loosen strictness of `Array.prototype.includes()` and `Set.prototype.has()` #60559

Closed sod closed 2 days ago

sod commented 2 days ago

πŸ” Search Terms

Example:

const values = ['foo', 'bar', 'baz'] as const;
type ValidValue = (typeof values)[number];

function isValueValid(value: string): value is ValidValue {
    return values.includes(value);
                          // ^^ ts error: Argument of type 'string' is not assignable to parameter of type '"foo" | "bar" | "baz"'
}

This error seems counter intuitive as the entire point of includes is to check if value in foo.includes(value) is one of foo. A Set and mySet.has(...) has the same issue.

playground

βœ… Viability Checklist

⭐ Suggestion

I'd expect typescript to not show an error here.

πŸ’» Use Cases

Now having to deal with the removal suppressImplicitAnyIndexErrors: true in typescript 5.6

MartinJohns commented 2 days ago

Duplicate of #60073 and many many more. Your search terms seem excessive, no wonder you didn't find any of them. I suggest limiting your search terms to a few related word, often with the in:title modifier.

IMO a type assertion is an appropriate workaround if this is intentional code.

sod commented 2 days ago

sorry. Thank you for your time.

I didn't see that improving this was already discussed and/or rejected.

sod commented 2 days ago

reopen because it's not a duplicate of #60073.

This ticket is not about making Array.prototype.includes() smarter. It's about not throwing an ts-error for 100% valid and deterministic usecase.

MartinJohns commented 2 days ago

This is a duplicate of #60073, #26255 and many others, ending up with #14520.

Your issue is the accepted type for includes(), same as the other.

And I have no clue what "strict property access" (from your use case) is about, that's completely unrelated.

sod commented 2 days ago

This is a duplicate of https://github.com/microsoft/TypeScript/issues/60073, https://github.com/microsoft/TypeScript/issues/26255 and many others, ending up with https://github.com/microsoft/TypeScript/issues/14520.

I aggree that this is a duplicate to https://github.com/microsoft/TypeScript/issues/26255. A 6 year old, with 27 upvotes closed duplicate. But a duplicate non the less.

Then I guess i have to write:

+ const inArray = (haystack: readonly any[], needle: string): boolean => haystack.includes(needle);
+ inArray(values, value)
- values.includes(value)

I hope nobody follows the recommendation on https://www.typescriptlang.org/tsconfig/#suppressImplicitAnyIndexErrors to use @ts-ignore, as that IMO is even worse.

And I have no clue what "strict property access" (from your use case) is about, that's completely unrelated.

Yes, strict property access made no sense. Removed that now from the description. This issue appeared when flicking "suppressImplicitAnyIndexErrors": true to false. A setting change that became mandatory with typescript@5.6.

Sadly I can't show it in the playground, because "suppressImplicitAnyIndexErrors": true isn't available anymore, even if you select an older version.


Fell free to close this issue.

MartinJohns commented 2 days ago

Again, you can just use a type assertion, IMO the cleanest approach: values.includes(value as ValidValue)

sod commented 2 days ago

values.includes(value as ValidValue)

Indeed that works. Not sure why. I internalized that whenever I had to restort to typecasting, that my underlying types or generics are incorrect.

Thank you.