Skip to content

Commit 98e9b3e

Browse files
committed
Move most potentially recursive types from isIdenticalTo into structuredTypeRelatedTo to match the non-identity relations
1 parent 82b8a4f commit 98e9b3e

5 files changed

+381
-27
lines changed

src/compiler/checker.ts

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11256,7 +11256,7 @@ namespace ts {
1125611256
function isIdenticalTo(source: Type, target: Type): Ternary {
1125711257
let result: Ternary;
1125811258
const flags = source.flags & target.flags;
11259-
if (flags & TypeFlags.Object) {
11259+
if (flags & TypeFlags.Object || flags & TypeFlags.IndexedAccess || flags & TypeFlags.Conditional || flags & TypeFlags.Index || flags & TypeFlags.Substitution) {
1126011260
return recursiveTypeRelatedTo(source, target, /*reportErrors*/ false);
1126111261
}
1126211262
if (flags & (TypeFlags.Union | TypeFlags.Intersection)) {
@@ -11266,32 +11266,6 @@ namespace ts {
1126611266
}
1126711267
}
1126811268
}
11269-
if (flags & TypeFlags.Index) {
11270-
return isRelatedTo((<IndexType>source).type, (<IndexType>target).type, /*reportErrors*/ false);
11271-
}
11272-
if (flags & TypeFlags.IndexedAccess) {
11273-
if (result = isRelatedTo((<IndexedAccessType>source).objectType, (<IndexedAccessType>target).objectType, /*reportErrors*/ false)) {
11274-
if (result &= isRelatedTo((<IndexedAccessType>source).indexType, (<IndexedAccessType>target).indexType, /*reportErrors*/ false)) {
11275-
return result;
11276-
}
11277-
}
11278-
}
11279-
if (flags & TypeFlags.Conditional) {
11280-
if ((<ConditionalType>source).root.isDistributive === (<ConditionalType>target).root.isDistributive) {
11281-
if (result = isRelatedTo((<ConditionalType>source).checkType, (<ConditionalType>target).checkType, /*reportErrors*/ false)) {
11282-
if (result &= isRelatedTo((<ConditionalType>source).extendsType, (<ConditionalType>target).extendsType, /*reportErrors*/ false)) {
11283-
if (result &= isRelatedTo(getTrueTypeFromConditionalType(<ConditionalType>source), getTrueTypeFromConditionalType(<ConditionalType>target), /*reportErrors*/ false)) {
11284-
if (result &= isRelatedTo(getFalseTypeFromConditionalType(<ConditionalType>source), getFalseTypeFromConditionalType(<ConditionalType>target), /*reportErrors*/ false)) {
11285-
return result;
11286-
}
11287-
}
11288-
}
11289-
}
11290-
}
11291-
}
11292-
if (flags & TypeFlags.Substitution) {
11293-
return isRelatedTo((<SubstitutionType>source).substitute, (<SubstitutionType>target).substitute, /*reportErrors*/ false);
11294-
}
1129511269
return Ternary.False;
1129611270
}
1129711271

@@ -11603,6 +11577,37 @@ namespace ts {
1160311577
}
1160411578

1160511579
function structuredTypeRelatedTo(source: Type, target: Type, reportErrors: boolean): Ternary {
11580+
const flags = source.flags & target.flags;
11581+
if (relation === identityRelation && !(flags & TypeFlags.Object)) {
11582+
if (flags & TypeFlags.Index) {
11583+
return isRelatedTo((<IndexType>source).type, (<IndexType>target).type, /*reportErrors*/ false);
11584+
}
11585+
let result = Ternary.False;
11586+
if (flags & TypeFlags.IndexedAccess) {
11587+
if (result = isRelatedTo((<IndexedAccessType>source).objectType, (<IndexedAccessType>target).objectType, /*reportErrors*/ false)) {
11588+
if (result &= isRelatedTo((<IndexedAccessType>source).indexType, (<IndexedAccessType>target).indexType, /*reportErrors*/ false)) {
11589+
return result;
11590+
}
11591+
}
11592+
}
11593+
if (flags & TypeFlags.Conditional) {
11594+
if ((<ConditionalType>source).root.isDistributive === (<ConditionalType>target).root.isDistributive) {
11595+
if (result = isRelatedTo((<ConditionalType>source).checkType, (<ConditionalType>target).checkType, /*reportErrors*/ false)) {
11596+
if (result &= isRelatedTo((<ConditionalType>source).extendsType, (<ConditionalType>target).extendsType, /*reportErrors*/ false)) {
11597+
if (result &= isRelatedTo(getTrueTypeFromConditionalType(<ConditionalType>source), getTrueTypeFromConditionalType(<ConditionalType>target), /*reportErrors*/ false)) {
11598+
if (result &= isRelatedTo(getFalseTypeFromConditionalType(<ConditionalType>source), getFalseTypeFromConditionalType(<ConditionalType>target), /*reportErrors*/ false)) {
11599+
return result;
11600+
}
11601+
}
11602+
}
11603+
}
11604+
}
11605+
}
11606+
if (flags & TypeFlags.Substitution) {
11607+
return isRelatedTo((<SubstitutionType>source).substitute, (<SubstitutionType>target).substitute, /*reportErrors*/ false);
11608+
}
11609+
return Ternary.False;
11610+
}
1160611611
let result: Ternary;
1160711612
let originalErrorInfo: DiagnosticMessageChain | undefined;
1160811613
const saveErrorInfo = errorInfo;
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//// [circularlySimplifyingConditionalTypesNoCrash.ts]
2+
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
3+
4+
type Shared< // Circularly self constraining type, defered thanks to mapping
5+
InjectedProps,
6+
DecorationTargetProps extends Shared<InjectedProps, DecorationTargetProps>
7+
> = {
8+
[P in Extract<keyof InjectedProps, keyof DecorationTargetProps>]: InjectedProps[P] extends DecorationTargetProps[P] ? DecorationTargetProps[P] : never;
9+
};
10+
11+
interface ComponentClass<P> {
12+
defaultProps?: Partial<P>; // Inference target is also mapped _and_ optional
13+
}
14+
15+
interface InferableComponentEnhancerWithProps<TInjectedProps, TNeedsProps> {
16+
<P extends Shared<TInjectedProps, P>>(
17+
component: ComponentClass<P>
18+
): ComponentClass<Omit<P, keyof Shared<TInjectedProps, P>> & TNeedsProps> & { WrappedComponent: ComponentClass<P> }
19+
} // Then intersected with and indexed via Omit and &
20+
21+
interface Connect { // Then strictly compared with another signature in its context
22+
<TStateProps, TOwnProps>(
23+
mapStateToProps: unknown,
24+
): InferableComponentEnhancerWithProps<TStateProps, TOwnProps>;
25+
26+
<TDispatchProps, TOwnProps>(
27+
mapStateToProps: null | undefined,
28+
mapDispatchToProps: unknown,
29+
mergeProps: null | undefined,
30+
options: unknown
31+
): InferableComponentEnhancerWithProps<TDispatchProps, TOwnProps>;
32+
}
33+
34+
declare var connect: Connect;
35+
36+
const myStoreConnect: Connect = function(
37+
mapStateToProps?: any,
38+
mapDispatchToProps?: any,
39+
mergeProps?: any,
40+
options: unknown = {},
41+
) {
42+
return connect(
43+
mapStateToProps,
44+
mapDispatchToProps,
45+
mergeProps,
46+
options,
47+
);
48+
};
49+
50+
//// [circularlySimplifyingConditionalTypesNoCrash.js]
51+
"use strict";
52+
var myStoreConnect = function (mapStateToProps, mapDispatchToProps, mergeProps, options) {
53+
if (options === void 0) { options = {}; }
54+
return connect(mapStateToProps, mapDispatchToProps, mergeProps, options);
55+
};
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
=== tests/cases/compiler/circularlySimplifyingConditionalTypesNoCrash.ts ===
2+
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
3+
>Omit : Symbol(Omit, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 0))
4+
>T : Symbol(T, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 10))
5+
>K : Symbol(K, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 12))
6+
>T : Symbol(T, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 10))
7+
>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --))
8+
>T : Symbol(T, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 10))
9+
>Exclude : Symbol(Exclude, Decl(lib.es5.d.ts, --, --))
10+
>T : Symbol(T, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 10))
11+
>K : Symbol(K, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 12))
12+
13+
type Shared< // Circularly self constraining type, defered thanks to mapping
14+
>Shared : Symbol(Shared, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 63))
15+
16+
InjectedProps,
17+
>InjectedProps : Symbol(InjectedProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 2, 12))
18+
19+
DecorationTargetProps extends Shared<InjectedProps, DecorationTargetProps>
20+
>DecorationTargetProps : Symbol(DecorationTargetProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 3, 18))
21+
>Shared : Symbol(Shared, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 63))
22+
>InjectedProps : Symbol(InjectedProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 2, 12))
23+
>DecorationTargetProps : Symbol(DecorationTargetProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 3, 18))
24+
25+
> = {
26+
[P in Extract<keyof InjectedProps, keyof DecorationTargetProps>]: InjectedProps[P] extends DecorationTargetProps[P] ? DecorationTargetProps[P] : never;
27+
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 6, 9))
28+
>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --))
29+
>InjectedProps : Symbol(InjectedProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 2, 12))
30+
>DecorationTargetProps : Symbol(DecorationTargetProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 3, 18))
31+
>InjectedProps : Symbol(InjectedProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 2, 12))
32+
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 6, 9))
33+
>DecorationTargetProps : Symbol(DecorationTargetProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 3, 18))
34+
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 6, 9))
35+
>DecorationTargetProps : Symbol(DecorationTargetProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 3, 18))
36+
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 6, 9))
37+
38+
};
39+
40+
interface ComponentClass<P> {
41+
>ComponentClass : Symbol(ComponentClass, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 7, 6))
42+
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 9, 25))
43+
44+
defaultProps?: Partial<P>; // Inference target is also mapped _and_ optional
45+
>defaultProps : Symbol(ComponentClass.defaultProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 9, 29))
46+
>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --))
47+
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 9, 25))
48+
}
49+
50+
interface InferableComponentEnhancerWithProps<TInjectedProps, TNeedsProps> {
51+
>InferableComponentEnhancerWithProps : Symbol(InferableComponentEnhancerWithProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 11, 1))
52+
>TInjectedProps : Symbol(TInjectedProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 13, 46))
53+
>TNeedsProps : Symbol(TNeedsProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 13, 61))
54+
55+
<P extends Shared<TInjectedProps, P>>(
56+
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 14, 5))
57+
>Shared : Symbol(Shared, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 63))
58+
>TInjectedProps : Symbol(TInjectedProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 13, 46))
59+
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 14, 5))
60+
61+
component: ComponentClass<P>
62+
>component : Symbol(component, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 14, 42))
63+
>ComponentClass : Symbol(ComponentClass, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 7, 6))
64+
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 14, 5))
65+
66+
): ComponentClass<Omit<P, keyof Shared<TInjectedProps, P>> & TNeedsProps> & { WrappedComponent: ComponentClass<P> }
67+
>ComponentClass : Symbol(ComponentClass, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 7, 6))
68+
>Omit : Symbol(Omit, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 0))
69+
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 14, 5))
70+
>Shared : Symbol(Shared, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 63))
71+
>TInjectedProps : Symbol(TInjectedProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 13, 46))
72+
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 14, 5))
73+
>TNeedsProps : Symbol(TNeedsProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 13, 61))
74+
>WrappedComponent : Symbol(WrappedComponent, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 16, 81))
75+
>ComponentClass : Symbol(ComponentClass, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 7, 6))
76+
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 14, 5))
77+
78+
} // Then intersected with and indexed via Omit and &
79+
80+
interface Connect { // Then strictly compared with another signature in its context
81+
>Connect : Symbol(Connect, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 17, 1))
82+
83+
<TStateProps, TOwnProps>(
84+
>TStateProps : Symbol(TStateProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 20, 5))
85+
>TOwnProps : Symbol(TOwnProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 20, 17))
86+
87+
mapStateToProps: unknown,
88+
>mapStateToProps : Symbol(mapStateToProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 20, 29))
89+
90+
): InferableComponentEnhancerWithProps<TStateProps, TOwnProps>;
91+
>InferableComponentEnhancerWithProps : Symbol(InferableComponentEnhancerWithProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 11, 1))
92+
>TStateProps : Symbol(TStateProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 20, 5))
93+
>TOwnProps : Symbol(TOwnProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 20, 17))
94+
95+
<TDispatchProps, TOwnProps>(
96+
>TDispatchProps : Symbol(TDispatchProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 24, 5))
97+
>TOwnProps : Symbol(TOwnProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 24, 20))
98+
99+
mapStateToProps: null | undefined,
100+
>mapStateToProps : Symbol(mapStateToProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 24, 32))
101+
102+
mapDispatchToProps: unknown,
103+
>mapDispatchToProps : Symbol(mapDispatchToProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 25, 42))
104+
105+
mergeProps: null | undefined,
106+
>mergeProps : Symbol(mergeProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 26, 36))
107+
108+
options: unknown
109+
>options : Symbol(options, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 27, 37))
110+
111+
): InferableComponentEnhancerWithProps<TDispatchProps, TOwnProps>;
112+
>InferableComponentEnhancerWithProps : Symbol(InferableComponentEnhancerWithProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 11, 1))
113+
>TDispatchProps : Symbol(TDispatchProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 24, 5))
114+
>TOwnProps : Symbol(TOwnProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 24, 20))
115+
}
116+
117+
declare var connect: Connect;
118+
>connect : Symbol(connect, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 32, 11))
119+
>Connect : Symbol(Connect, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 17, 1))
120+
121+
const myStoreConnect: Connect = function(
122+
>myStoreConnect : Symbol(myStoreConnect, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 34, 5))
123+
>Connect : Symbol(Connect, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 17, 1))
124+
125+
mapStateToProps?: any,
126+
>mapStateToProps : Symbol(mapStateToProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 34, 41))
127+
128+
mapDispatchToProps?: any,
129+
>mapDispatchToProps : Symbol(mapDispatchToProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 35, 26))
130+
131+
mergeProps?: any,
132+
>mergeProps : Symbol(mergeProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 36, 29))
133+
134+
options: unknown = {},
135+
>options : Symbol(options, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 37, 21))
136+
137+
) {
138+
return connect(
139+
>connect : Symbol(connect, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 32, 11))
140+
141+
mapStateToProps,
142+
>mapStateToProps : Symbol(mapStateToProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 34, 41))
143+
144+
mapDispatchToProps,
145+
>mapDispatchToProps : Symbol(mapDispatchToProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 35, 26))
146+
147+
mergeProps,
148+
>mergeProps : Symbol(mergeProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 36, 29))
149+
150+
options,
151+
>options : Symbol(options, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 37, 21))
152+
153+
);
154+
};
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
=== tests/cases/compiler/circularlySimplifyingConditionalTypesNoCrash.ts ===
2+
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
3+
>Omit : Pick<T, Exclude<keyof T, K>>
4+
5+
type Shared< // Circularly self constraining type, defered thanks to mapping
6+
>Shared : Shared<InjectedProps, DecorationTargetProps>
7+
8+
InjectedProps,
9+
DecorationTargetProps extends Shared<InjectedProps, DecorationTargetProps>
10+
> = {
11+
[P in Extract<keyof InjectedProps, keyof DecorationTargetProps>]: InjectedProps[P] extends DecorationTargetProps[P] ? DecorationTargetProps[P] : never;
12+
};
13+
14+
interface ComponentClass<P> {
15+
defaultProps?: Partial<P>; // Inference target is also mapped _and_ optional
16+
>defaultProps : Partial<P> | undefined
17+
}
18+
19+
interface InferableComponentEnhancerWithProps<TInjectedProps, TNeedsProps> {
20+
<P extends Shared<TInjectedProps, P>>(
21+
component: ComponentClass<P>
22+
>component : ComponentClass<P>
23+
24+
): ComponentClass<Omit<P, keyof Shared<TInjectedProps, P>> & TNeedsProps> & { WrappedComponent: ComponentClass<P> }
25+
>WrappedComponent : ComponentClass<P>
26+
27+
} // Then intersected with and indexed via Omit and &
28+
29+
interface Connect { // Then strictly compared with another signature in its context
30+
<TStateProps, TOwnProps>(
31+
mapStateToProps: unknown,
32+
>mapStateToProps : unknown
33+
34+
): InferableComponentEnhancerWithProps<TStateProps, TOwnProps>;
35+
36+
<TDispatchProps, TOwnProps>(
37+
mapStateToProps: null | undefined,
38+
>mapStateToProps : null | undefined
39+
>null : null
40+
41+
mapDispatchToProps: unknown,
42+
>mapDispatchToProps : unknown
43+
44+
mergeProps: null | undefined,
45+
>mergeProps : null | undefined
46+
>null : null
47+
48+
options: unknown
49+
>options : unknown
50+
51+
): InferableComponentEnhancerWithProps<TDispatchProps, TOwnProps>;
52+
}
53+
54+
declare var connect: Connect;
55+
>connect : Connect
56+
57+
const myStoreConnect: Connect = function(
58+
>myStoreConnect : Connect
59+
>function( mapStateToProps?: any, mapDispatchToProps?: any, mergeProps?: any, options: unknown = {},) { return connect( mapStateToProps, mapDispatchToProps, mergeProps, options, );} : (mapStateToProps?: any, mapDispatchToProps?: any, mergeProps?: any, options?: unknown) => InferableComponentEnhancerWithProps<{}, {}>
60+
61+
mapStateToProps?: any,
62+
>mapStateToProps : any
63+
64+
mapDispatchToProps?: any,
65+
>mapDispatchToProps : any
66+
67+
mergeProps?: any,
68+
>mergeProps : any
69+
70+
options: unknown = {},
71+
>options : unknown
72+
>{} : {}
73+
74+
) {
75+
return connect(
76+
>connect( mapStateToProps, mapDispatchToProps, mergeProps, options, ) : InferableComponentEnhancerWithProps<{}, {}>
77+
>connect : Connect
78+
79+
mapStateToProps,
80+
>mapStateToProps : any
81+
82+
mapDispatchToProps,
83+
>mapDispatchToProps : any
84+
85+
mergeProps,
86+
>mergeProps : any
87+
88+
options,
89+
>options : unknown
90+
91+
);
92+
};

0 commit comments

Comments
 (0)