microsoft / microsoft/TypeScript
Ensure 'in' does not operate on primitive types
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 111k
- Forks
- 14.3k
- Avg merge
- 2d 4h
- Merged PRs (30d)
- 132
Description
Bug Report
🔎 Search Terms
operator in exception crash unhandled
🕗 Version & Regression Information
This is the behavior in every version I tried
⏯ Playground Link
Playground link with relevant code
💻 Code
const mustBeObject = (thing: object) => thing
const hasKey = <A extends object | null | string | number, K extends string | number | symbol>(
thing: A,
key: K,
): boolean => {
if (thing && typeof thing === 'object') {
mustBeObject(thing);
return key in thing; // no error
}
return key in thing; // error
};
hasKey(123, 'hello');
🙁 Actual behavior
TS should expect A to be an object
🙂 Expected behavior
TS didn't detect the potential crash
This is a follow-up to #41317. In #41928, we decided that we should implement a more conservative check that only ensures that the resolved constraint of the right operand to the in operator is not assignable to a primitive. This is a negative check ensuring that the type of the right operand does not explicitly extend a primitive type. This solution does not yet cover the original example shown above.
The alternative we discussed was a positive check that the type of the right expression cannot possibly extend a primitive type. We could do this either by checking that the type of right operand (not its resolved constraint!) is not assignable to a primitive or by checking that this type is assignable to object.
I am reopening this issue because with #43183 (🎉) the original reason why we went with the more conservative (from a breaking change point of view) check will soon not be a limitation any more. Therefore, code like
if (typeof val === 'object' && '__isMaybe' in val) {
does not represent a problem anymore because val can be narrowed even if its type is a type parameter as long as it extends a union (see https://github.com/microsoft/TypeScript/pull/41928#issuecomment-743356094 for the original discussion).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the linked TypeScript Playground and the in operator example, then read the discussion of #41317, #41928, and #43183. Compare the current handling of generic right operands against the stated primitive-type crash; done means the checker reliably rejects unsafe in expressions without breaking the narrowing behavior described in the issue.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100