Repository navigation
exactOptionalPropertyTypes: strict type equality is too lenientΒ #61547
Copy link
Copy link
Closed
Labels
Not a DefectThis behavior is one of several equally-correct optionsThis behavior is one of several equally-correct options
Milestone
Description
π Search Terms
"exactOptionalPropertyTypes", "strict type equality"
π Version & Regression Information
- Tested in TypeScript 5.8.2
β― Playground Link
π» 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
- Small repository that demonstrates the bug: https://github.com/rauschma/exactOptionalPropertyTypes
- Related issue elsewhere: false equality with
exactOptionalPropertyTypesΒ mmkal/expect-type#128 - Related Zod bug: .optional() and --exactOptionalPropertyTypesΒ colinhacks/zod#635
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
Not a DefectThis behavior is one of several equally-correct optionsThis behavior is one of several equally-correct options
Activity
louwers commentedon Apr 7, 2025
I think this is not so much a bug with TypeScript, but just a bug with the
Equalhelper function that was shared in 2018.rauschma commentedon Apr 7, 2025
So maybe this is more of a feature suggestion than a bug report? People need this functionality:
louwers commentedon Apr 7, 2025
The issue you linked is a feature suggestion for this. #27024
Someone opened a new issue #48100
HansBrende commentedon May 9, 2025
It does indicate a bug in TypeScript, in my opinion. I think it boils down to "a spot was missed" whenever they were implementing
exactOptionalPropertyTypes. I point out exactly where that spot was missed in the reference above πHansBrende commentedon Sep 30, 2025
Axel Rauschmayer (@rauschma) this bug is now fixed, just got merged #61683!
rauschma commentedon Sep 30, 2025
Nice! Thanks Hans Brende (@HansBrende)!