microsoft / microsoft/TypeScript

Type 'never' incorrectly inferred for mixed primitive type properties assignment with strictNullChecks disabled

Open
#59,969 2 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Bug Domain: Indexed Access Types Help Wanted
Dominant language
Go
Stars
111k
Forks
14.3k
Avg merge
2d 4h
Merged PRs (30d)
132

Description

🔎 Search Terms

strictNullChecks false assign never

🕗 Version & Regression Information
  • typescript 3.6.0-dev.20190612, 3.6.0, and every version on TS Playground between 3.6.1 and nightly (5.7.0-dev.20240914)
  • This changed between versions 3.6.0-dev.20190611 and 3.6.0-dev.20190612
  • This changed in commit or PR 74c6bc1f85c2ab36fdb789aa0ef6ee5dbde5afdd (#31708)
    • No error in da2aa9781e582bebd531750a4b8a81d9f8be2906
⏯ Playground Link

https://www.typescriptlang.org/play/?strictNullChecks=false&ts=5.6.2#code/C4TwDgpgBA8gRgKygXigbwFBSmATgezAEYB+ALigGdhcBLAOwHMBuLHAsAJnKpoZbZ5CAZh70ArgFs4EXK2xCwAFh4ARAIbAIrAL6sMAegNQAwusrQiFAIIAbW+0KzgtCJSgALdQDdowD9CU6pJ+4NAAFNR0TACUGADG+PTUUABmRChQ4fiIFPAIADRQANYQIBQARIpEFVAAPlBVHJwVMSgAfOhsOQgA2qUgALqZ4vQAJhCpDBBjzFBGUABq6ra0Y92I-WXDqBL2cwvLq2NQAO4B9Lx08cAAcuL2JgHxxe607qkrFhh6GIbGZgsUE4FAAChxnK53F5fFAxrRUqlZBB6MB2LRJLQXLDQJB3JE+Ex6lAJNJZHFEsk0alOJlsrlYIgigNKtVag0miJWh0utgelshiNxpNprN5sYAKK4Ai4M4XK60G73R7PV5Qd5pL4QAB0UAlAA9IDcZlBgPgoDIoN4VmsNn0BjsSQ9bAdJdL8LhdQajVoTmaLdBrcc5SiFUrnU8IC83h8tWxKSkg5l+Q7XUsbSdwrjoBqovxiaSZLg4mwFgB1D3FdQEUbrbAJtE9WmoHpQczoao8Wsi+gzIqKUQUbtTXtjX58xCcAWO4eitNHW0ThBTh2ZPYu8Xp4PnUN58MqqNqjWfWzfbCHDNQCC+S6nLEeKAAAwg+vUNxgYBcSRW4KcuFAAAqYSUBQNDiBAj5FP4+DiIwD4yDCtAenCCJIrglBsBMtgQFoUAptsuj6AsgLQMIYIQv+ULqvQ8S2OIEwWvg-jopi2LQOo4x4YgUZotm+J5kSDQaFoFJJCkqTCHSPR5EyJRlKyHA1MSnLKNyyCdJgS7TkKEwjjM84Zna2m7M6BnbvKe53BGqoxpqp4QD8zBAA

💻 Code
type Obj = {
  prop1?: string;
  prop2?: string;
  prop3?: number;
  prop4?: Date;
};

// Case 1: All properties have the same type (string)
const f1 = (obj: Obj, key: "prop1" | "prop2") => {
  obj[key] = undefined; // Valid
  obj[key] = null; // Valid when strictNullChecks is false
};

// Case 2: Properties have different primitive types (string | number)
const f2 = (obj: Obj, key: "prop1" | "prop3") => {
  obj[key] = undefined; // Error when strictNullChecks is false. Expected to be valid
  obj[key] = null; // Error. Expected to be valid when strictNullChecks is false
  const val = obj[key]; // Valid (type is string | number)

  // Workaround
  const obj2 = obj as {prop1?: undefined, prop3?: undefined};
  obj2[key] = undefined; // Valid
  obj2[key] = null; // Valid when strictNullChecks is false
  // Valid even with `exactOptionalPropertyTypes: true`, though behavior differs
  delete obj[key];
};

// Case 3: Properties include both primitive and object types (string | Date)
const f3 = (obj: Obj, key: "prop1" | "prop4") => {
  obj[key] = undefined; // Valid
  obj[key] = null; // Valid when strictNullChecks is false
};
🙁 Actual behavior
  1. In Case 2, when strictNullChecks is false:

    • Assigning undefined results in an error: "Type 'undefined' is not assignable to type 'never'.(TS2322)"
    • Assigning null always results in an error: "Type 'null' is not assignable to type 'never'.(TS2322)"
  2. The behavior is inconsistent across different combinations of property types.

🙂 Expected behavior

Since all properties in Obj are optional, it should be possible to assign undefined to obj[key] regardless of the strictNullChecks setting, unless exactOptionalPropertyTypes is true (which cannot be used with strictNullChecks: false).

Additionally, when strictNullChecks is false, assigning null should be allowed for all cases.

Additional information about the issue

No response

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

Start with the TypeScript Playground reproduction and compare the behavior of cases 1–3 with strictNullChecks disabled. Trace how indexed assignment types are inferred for unions of optional properties, using the reported regression range and commit #31708 as the entry point. Done means undefined and null assignments follow the stated expectations without breaking exactOptionalPropertyTypes behavior.

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
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.