microsoft / microsoft/TypeScript

`noUncheckedIndexedAccess` should forbid unsound `Record<string, string>` → `Record<"k", string>` coercion

Open
#62,796 7 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Awaiting More Feedback Suggestion
Dominant language
Go
Stars
111k
Forks
14.3k
Avg merge
2d 4h
Merged PRs (30d)
132

Description

🔎 Search Terms

coercion, noUncheckedIndexedAccess, Record, unsound

🕗 Version & Regression Information
  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about noUncheckedIndexedAccess
⏯ Playground Link

https://www.typescriptlang.org/play/?noUncheckedIndexedAccess=true&ts=5.9.3#code/DYUwLgBAhgXBBKIDGB7ATgEwDwGcxoEsA7AcwBoI9DSA+CAXggG8BfAbgChRIAjORVJiwAiANbCKVYiTqMobCAHpFEAK5EcKdRi7gIPUXCmkG+gHSjOBs2BQAZFAHcQaAMJQcIABQBKBcogAMygCYBxoSDR1MAIAWxAOIA

💻 Code
let a: Record<string, string> = {};
let b: Record<"k", string> = a; // unsound
let bk: string = b.k;
bk.toLowerCase(); // fails at runtime
🙁 Actual behavior

No TypeScript errors.

🙂 Expected behavior

By enabling noUncheckedIndexedAccess, I’ve opted in to stricter errors that prevent mistakes where a potentially undefined record element is assumed to be defined. The coercion from a: Record<string, string> to Record<"k", string> is such a mistake, since it assumes that a.k is defined. So TypeScript should forbid this coercion when noUncheckedIndexedAccess is enabled.

Additional information about the issue

noUncheckedIndexedAccess already causes TypeScript to correctly reject the equivalent unsound coercion Record<string, string>{k: string}.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the example in the linked TypeScript Playground with noUncheckedIndexedAccess enabled, then compare the Record<string, string> to Record<"k", string> case with the equivalent coercion to { k: string }, which is already rejected. Done means the unsound Record coercion is rejected under noUncheckedIndexedAccess without changing the expected behavior described in the issue.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.