Skip to content
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

exactOptionalPropertyTypes: strict type equality is too lenient #61547

Open
rauschma opened this issue Apr 7, 2025 · 4 comments
Open

exactOptionalPropertyTypes: strict type equality is too lenient #61547

rauschma opened this issue Apr 7, 2025 · 4 comments
Labels
Not a Defect This behavior is one of several equally-correct options

Comments

@rauschma
Copy link

rauschma commented Apr 7, 2025

πŸ”Ž Search Terms

"exactOptionalPropertyTypes", "strict type equality"

πŸ•— Version & Regression Information

  • Tested in TypeScript 5.8.2

⏯ Playground Link

https://www.typescriptlang.org/play/?exactOptionalPropertyTypes=true#code/PTAEFMA8EMGMBcDyAHeBLA9gO2gGwAoBOGy4h8AngCoWkDOAXAFBOWmhUCMoAvKAN5NQoZMWQB+BqDrxCaLAHMANEwC+rWuA4AmXgKEixk0AFcsAE3AAzeeHOgAPtNnzlajewD6egNoGQoIAy5Bzc0BY6oNCEWrDYdGiW0fYycgi4FBAAjiZ4BgCCdHRk8AA8AKLZeCUGwlxKOgYAfI0qwgFckeFUulFaWBjwoLFY8Yl2oLgYGEXpWTm4+YXFJQByAyUAMlNFFfPVwrWc9d1Nza2g7bpodKD9g9CFaAo4AEa4WvAYIYtF5KvrBXiz2gb3A+wOdQawmaLX8YA610ij2BoNAnyhoEBy0BT1e73BtW0x04pxUAF0ANwsNhaLF-TxUCCQeDgCw3WQmcCNPQANwwCSpAUAvBuAI-2OKkANZor4uBQKMjOVKDGlzPBoSgAOlAAGUMCZCLBwFIABbweDIRggBTq40mF4a2IAW2AAFk0LBiHQMFZ4MAaKRtR60KhgNc6Jy6MBtAB2AAM2gALABiMOcp2O1nwAC0Ce0nAArNoAJwANnzsY8Wl2VQAGvUAJrcngGAAUJSojRbAEpeNzGVAWWzQDXQOJQNwpNoewPWeY6K3252ezw+0zB3PQPXR+PQJOe2OOVopFY8EUDFSVVtpuBq7gSnXN02DD4a2S17Obj562SDGOW1+3xnIcXzfA9CE5XdQBPXAii7Axj1PcBz0rUA1lKAAhd8hxeKZ3jCJ82jAAADW8iNAF5wFgaATCKUAAHcwmVL5oD5BJUPWMIKG5CjXFAIjoKKMiMEIPjDyIgxbxKdD6kPbkgI3Q8am3ASkIOSCW0k6SoMQuTmQ-NFwK0MCIKkLBwB5Mg4OEC9NExZE8TBKgonleB6l1fVDSbUAfHcg1wEAvTgKcwgXNAgyTO0mDwCpIA

πŸ’» Code

// exactOptionalPropertyTypes:

type T1 = {
  prop?: string,
}
type T2 = {
  prop?: undefined | string,
}
type _ = [
  // ❌ T1 and T2 are considered strictly equal
  Assert<Equal<
    T1, T2
  >>,
  // T2 is not assignable to T1
  Assert<Not<Assignable<
    T1, T2
  >>>,
  // T1 is assignable to T2
  Assert<Assignable<
    T2, T1
  >>,
  // T1 and T2 are not considered loosely equal
  Assert<Not<LooseEqual<
    T1, T2
  >>>,
];

type Assert<_T extends true> = void;
// 🟒 Trick to trigger strict type equality. Source: https://github.com/Microsoft/TypeScript/issues/27024#issuecomment-421529650
type Equal<X, Y> =
  (<T>() => T extends X ? 1 : 2) extends
  (<T>() => T extends Y ? 1 : 2) ? true : false
  ;
type LooseEqual<X, Y> =
  [X] extends [Y]
  ? ([Y] extends [X] ? true : false)
  : false
  ;
type Not<B extends boolean> =
  // `Equal` because want to avoid Not<any> being `false` or `true`
  Equal<B, true> extends true
    ? false
    : (Equal<B, false> extends true ? true : never)
  ;
type Assignable<Target, Source> = [Source] extends [Target] ? true : false;

πŸ™ Actual behavior

T1 and T2 are considered to be strictly equal – even though T2 is not assignable to T1.

πŸ™‚ Expected behavior

T1 and T2 should not be considered strictly equal.

Additional information about the issue

@louwers
Copy link

louwers commented Apr 7, 2025

I think this is not so much a bug with TypeScript, but just a bug with the Equal helper function that was shared in 2018.

@rauschma
Copy link
Author

rauschma commented Apr 7, 2025

So maybe this is more of a feature suggestion than a bug report? People need this functionality:

@louwers
Copy link

louwers commented Apr 7, 2025

The issue you linked is a feature suggestion for this. #27024

Someone opened a new issue #48100

@RyanCavanaugh RyanCavanaugh added the Not a Defect This behavior is one of several equally-correct options label Apr 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Not a Defect This behavior is one of several equally-correct options
Projects
None yet
Development

No branches or pull requests

3 participants