Skip to content

Commit

Permalink
Move most potentially recursive types from isIdenticalTo into structu…
Browse files Browse the repository at this point in the history
…redTypeRelatedTo to match the non-identity relations
  • Loading branch information
weswigham committed Aug 23, 2018
1 parent 82b8a4f commit 98e9b3e
Show file tree
Hide file tree
Showing 5 changed files with 381 additions and 27 deletions.
59 changes: 32 additions & 27 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11256,7 +11256,7 @@ namespace ts {
function isIdenticalTo(source: Type, target: Type): Ternary {
let result: Ternary;
const flags = source.flags & target.flags;
if (flags & TypeFlags.Object) {
if (flags & TypeFlags.Object || flags & TypeFlags.IndexedAccess || flags & TypeFlags.Conditional || flags & TypeFlags.Index || flags & TypeFlags.Substitution) {
return recursiveTypeRelatedTo(source, target, /*reportErrors*/ false);
}
if (flags & (TypeFlags.Union | TypeFlags.Intersection)) {
Expand All @@ -11266,32 +11266,6 @@ namespace ts {
}
}
}
if (flags & TypeFlags.Index) {
return isRelatedTo((<IndexType>source).type, (<IndexType>target).type, /*reportErrors*/ false);
}
if (flags & TypeFlags.IndexedAccess) {
if (result = isRelatedTo((<IndexedAccessType>source).objectType, (<IndexedAccessType>target).objectType, /*reportErrors*/ false)) {
if (result &= isRelatedTo((<IndexedAccessType>source).indexType, (<IndexedAccessType>target).indexType, /*reportErrors*/ false)) {
return result;
}
}
}
if (flags & TypeFlags.Conditional) {
if ((<ConditionalType>source).root.isDistributive === (<ConditionalType>target).root.isDistributive) {
if (result = isRelatedTo((<ConditionalType>source).checkType, (<ConditionalType>target).checkType, /*reportErrors*/ false)) {
if (result &= isRelatedTo((<ConditionalType>source).extendsType, (<ConditionalType>target).extendsType, /*reportErrors*/ false)) {
if (result &= isRelatedTo(getTrueTypeFromConditionalType(<ConditionalType>source), getTrueTypeFromConditionalType(<ConditionalType>target), /*reportErrors*/ false)) {
if (result &= isRelatedTo(getFalseTypeFromConditionalType(<ConditionalType>source), getFalseTypeFromConditionalType(<ConditionalType>target), /*reportErrors*/ false)) {
return result;
}
}
}
}
}
}
if (flags & TypeFlags.Substitution) {
return isRelatedTo((<SubstitutionType>source).substitute, (<SubstitutionType>target).substitute, /*reportErrors*/ false);
}
return Ternary.False;
}

Expand Down Expand Up @@ -11603,6 +11577,37 @@ namespace ts {
}

function structuredTypeRelatedTo(source: Type, target: Type, reportErrors: boolean): Ternary {
const flags = source.flags & target.flags;
if (relation === identityRelation && !(flags & TypeFlags.Object)) {
if (flags & TypeFlags.Index) {
return isRelatedTo((<IndexType>source).type, (<IndexType>target).type, /*reportErrors*/ false);
}
let result = Ternary.False;
if (flags & TypeFlags.IndexedAccess) {
if (result = isRelatedTo((<IndexedAccessType>source).objectType, (<IndexedAccessType>target).objectType, /*reportErrors*/ false)) {
if (result &= isRelatedTo((<IndexedAccessType>source).indexType, (<IndexedAccessType>target).indexType, /*reportErrors*/ false)) {
return result;
}
}
}
if (flags & TypeFlags.Conditional) {
if ((<ConditionalType>source).root.isDistributive === (<ConditionalType>target).root.isDistributive) {
if (result = isRelatedTo((<ConditionalType>source).checkType, (<ConditionalType>target).checkType, /*reportErrors*/ false)) {
if (result &= isRelatedTo((<ConditionalType>source).extendsType, (<ConditionalType>target).extendsType, /*reportErrors*/ false)) {
if (result &= isRelatedTo(getTrueTypeFromConditionalType(<ConditionalType>source), getTrueTypeFromConditionalType(<ConditionalType>target), /*reportErrors*/ false)) {
if (result &= isRelatedTo(getFalseTypeFromConditionalType(<ConditionalType>source), getFalseTypeFromConditionalType(<ConditionalType>target), /*reportErrors*/ false)) {
return result;
}
}
}
}
}
}
if (flags & TypeFlags.Substitution) {
return isRelatedTo((<SubstitutionType>source).substitute, (<SubstitutionType>target).substitute, /*reportErrors*/ false);
}
return Ternary.False;
}
let result: Ternary;
let originalErrorInfo: DiagnosticMessageChain | undefined;
const saveErrorInfo = errorInfo;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//// [circularlySimplifyingConditionalTypesNoCrash.ts]
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;

type Shared< // Circularly self constraining type, defered thanks to mapping
InjectedProps,
DecorationTargetProps extends Shared<InjectedProps, DecorationTargetProps>
> = {
[P in Extract<keyof InjectedProps, keyof DecorationTargetProps>]: InjectedProps[P] extends DecorationTargetProps[P] ? DecorationTargetProps[P] : never;
};

interface ComponentClass<P> {
defaultProps?: Partial<P>; // Inference target is also mapped _and_ optional
}

interface InferableComponentEnhancerWithProps<TInjectedProps, TNeedsProps> {
<P extends Shared<TInjectedProps, P>>(
component: ComponentClass<P>
): ComponentClass<Omit<P, keyof Shared<TInjectedProps, P>> & TNeedsProps> & { WrappedComponent: ComponentClass<P> }
} // Then intersected with and indexed via Omit and &

interface Connect { // Then strictly compared with another signature in its context
<TStateProps, TOwnProps>(
mapStateToProps: unknown,
): InferableComponentEnhancerWithProps<TStateProps, TOwnProps>;

<TDispatchProps, TOwnProps>(
mapStateToProps: null | undefined,
mapDispatchToProps: unknown,
mergeProps: null | undefined,
options: unknown
): InferableComponentEnhancerWithProps<TDispatchProps, TOwnProps>;
}

declare var connect: Connect;

const myStoreConnect: Connect = function(
mapStateToProps?: any,
mapDispatchToProps?: any,
mergeProps?: any,
options: unknown = {},
) {
return connect(
mapStateToProps,
mapDispatchToProps,
mergeProps,
options,
);
};

//// [circularlySimplifyingConditionalTypesNoCrash.js]
"use strict";
var myStoreConnect = function (mapStateToProps, mapDispatchToProps, mergeProps, options) {
if (options === void 0) { options = {}; }
return connect(mapStateToProps, mapDispatchToProps, mergeProps, options);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
=== tests/cases/compiler/circularlySimplifyingConditionalTypesNoCrash.ts ===
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
>Omit : Symbol(Omit, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 0))
>T : Symbol(T, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 10))
>K : Symbol(K, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 12))
>T : Symbol(T, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 10))
>Pick : Symbol(Pick, Decl(lib.es5.d.ts, --, --))
>T : Symbol(T, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 10))
>Exclude : Symbol(Exclude, Decl(lib.es5.d.ts, --, --))
>T : Symbol(T, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 10))
>K : Symbol(K, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 12))

type Shared< // Circularly self constraining type, defered thanks to mapping
>Shared : Symbol(Shared, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 63))

InjectedProps,
>InjectedProps : Symbol(InjectedProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 2, 12))

DecorationTargetProps extends Shared<InjectedProps, DecorationTargetProps>
>DecorationTargetProps : Symbol(DecorationTargetProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 3, 18))
>Shared : Symbol(Shared, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 63))
>InjectedProps : Symbol(InjectedProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 2, 12))
>DecorationTargetProps : Symbol(DecorationTargetProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 3, 18))

> = {
[P in Extract<keyof InjectedProps, keyof DecorationTargetProps>]: InjectedProps[P] extends DecorationTargetProps[P] ? DecorationTargetProps[P] : never;
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 6, 9))
>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --))
>InjectedProps : Symbol(InjectedProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 2, 12))
>DecorationTargetProps : Symbol(DecorationTargetProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 3, 18))
>InjectedProps : Symbol(InjectedProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 2, 12))
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 6, 9))
>DecorationTargetProps : Symbol(DecorationTargetProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 3, 18))
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 6, 9))
>DecorationTargetProps : Symbol(DecorationTargetProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 3, 18))
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 6, 9))

};

interface ComponentClass<P> {
>ComponentClass : Symbol(ComponentClass, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 7, 6))
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 9, 25))

defaultProps?: Partial<P>; // Inference target is also mapped _and_ optional
>defaultProps : Symbol(ComponentClass.defaultProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 9, 29))
>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --))
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 9, 25))
}

interface InferableComponentEnhancerWithProps<TInjectedProps, TNeedsProps> {
>InferableComponentEnhancerWithProps : Symbol(InferableComponentEnhancerWithProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 11, 1))
>TInjectedProps : Symbol(TInjectedProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 13, 46))
>TNeedsProps : Symbol(TNeedsProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 13, 61))

<P extends Shared<TInjectedProps, P>>(
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 14, 5))
>Shared : Symbol(Shared, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 63))
>TInjectedProps : Symbol(TInjectedProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 13, 46))
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 14, 5))

component: ComponentClass<P>
>component : Symbol(component, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 14, 42))
>ComponentClass : Symbol(ComponentClass, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 7, 6))
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 14, 5))

): ComponentClass<Omit<P, keyof Shared<TInjectedProps, P>> & TNeedsProps> & { WrappedComponent: ComponentClass<P> }
>ComponentClass : Symbol(ComponentClass, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 7, 6))
>Omit : Symbol(Omit, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 0))
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 14, 5))
>Shared : Symbol(Shared, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 0, 63))
>TInjectedProps : Symbol(TInjectedProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 13, 46))
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 14, 5))
>TNeedsProps : Symbol(TNeedsProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 13, 61))
>WrappedComponent : Symbol(WrappedComponent, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 16, 81))
>ComponentClass : Symbol(ComponentClass, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 7, 6))
>P : Symbol(P, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 14, 5))

} // Then intersected with and indexed via Omit and &

interface Connect { // Then strictly compared with another signature in its context
>Connect : Symbol(Connect, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 17, 1))

<TStateProps, TOwnProps>(
>TStateProps : Symbol(TStateProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 20, 5))
>TOwnProps : Symbol(TOwnProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 20, 17))

mapStateToProps: unknown,
>mapStateToProps : Symbol(mapStateToProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 20, 29))

): InferableComponentEnhancerWithProps<TStateProps, TOwnProps>;
>InferableComponentEnhancerWithProps : Symbol(InferableComponentEnhancerWithProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 11, 1))
>TStateProps : Symbol(TStateProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 20, 5))
>TOwnProps : Symbol(TOwnProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 20, 17))

<TDispatchProps, TOwnProps>(
>TDispatchProps : Symbol(TDispatchProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 24, 5))
>TOwnProps : Symbol(TOwnProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 24, 20))

mapStateToProps: null | undefined,
>mapStateToProps : Symbol(mapStateToProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 24, 32))

mapDispatchToProps: unknown,
>mapDispatchToProps : Symbol(mapDispatchToProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 25, 42))

mergeProps: null | undefined,
>mergeProps : Symbol(mergeProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 26, 36))

options: unknown
>options : Symbol(options, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 27, 37))

): InferableComponentEnhancerWithProps<TDispatchProps, TOwnProps>;
>InferableComponentEnhancerWithProps : Symbol(InferableComponentEnhancerWithProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 11, 1))
>TDispatchProps : Symbol(TDispatchProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 24, 5))
>TOwnProps : Symbol(TOwnProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 24, 20))
}

declare var connect: Connect;
>connect : Symbol(connect, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 32, 11))
>Connect : Symbol(Connect, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 17, 1))

const myStoreConnect: Connect = function(
>myStoreConnect : Symbol(myStoreConnect, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 34, 5))
>Connect : Symbol(Connect, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 17, 1))

mapStateToProps?: any,
>mapStateToProps : Symbol(mapStateToProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 34, 41))

mapDispatchToProps?: any,
>mapDispatchToProps : Symbol(mapDispatchToProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 35, 26))

mergeProps?: any,
>mergeProps : Symbol(mergeProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 36, 29))

options: unknown = {},
>options : Symbol(options, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 37, 21))

) {
return connect(
>connect : Symbol(connect, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 32, 11))

mapStateToProps,
>mapStateToProps : Symbol(mapStateToProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 34, 41))

mapDispatchToProps,
>mapDispatchToProps : Symbol(mapDispatchToProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 35, 26))

mergeProps,
>mergeProps : Symbol(mergeProps, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 36, 29))

options,
>options : Symbol(options, Decl(circularlySimplifyingConditionalTypesNoCrash.ts, 37, 21))

);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
=== tests/cases/compiler/circularlySimplifyingConditionalTypesNoCrash.ts ===
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
>Omit : Pick<T, Exclude<keyof T, K>>

type Shared< // Circularly self constraining type, defered thanks to mapping
>Shared : Shared<InjectedProps, DecorationTargetProps>

InjectedProps,
DecorationTargetProps extends Shared<InjectedProps, DecorationTargetProps>
> = {
[P in Extract<keyof InjectedProps, keyof DecorationTargetProps>]: InjectedProps[P] extends DecorationTargetProps[P] ? DecorationTargetProps[P] : never;
};

interface ComponentClass<P> {
defaultProps?: Partial<P>; // Inference target is also mapped _and_ optional
>defaultProps : Partial<P> | undefined
}

interface InferableComponentEnhancerWithProps<TInjectedProps, TNeedsProps> {
<P extends Shared<TInjectedProps, P>>(
component: ComponentClass<P>
>component : ComponentClass<P>

): ComponentClass<Omit<P, keyof Shared<TInjectedProps, P>> & TNeedsProps> & { WrappedComponent: ComponentClass<P> }
>WrappedComponent : ComponentClass<P>

} // Then intersected with and indexed via Omit and &

interface Connect { // Then strictly compared with another signature in its context
<TStateProps, TOwnProps>(
mapStateToProps: unknown,
>mapStateToProps : unknown

): InferableComponentEnhancerWithProps<TStateProps, TOwnProps>;

<TDispatchProps, TOwnProps>(
mapStateToProps: null | undefined,
>mapStateToProps : null | undefined
>null : null

mapDispatchToProps: unknown,
>mapDispatchToProps : unknown

mergeProps: null | undefined,
>mergeProps : null | undefined
>null : null

options: unknown
>options : unknown

): InferableComponentEnhancerWithProps<TDispatchProps, TOwnProps>;
}

declare var connect: Connect;
>connect : Connect

const myStoreConnect: Connect = function(
>myStoreConnect : Connect
>function( mapStateToProps?: any, mapDispatchToProps?: any, mergeProps?: any, options: unknown = {},) { return connect( mapStateToProps, mapDispatchToProps, mergeProps, options, );} : (mapStateToProps?: any, mapDispatchToProps?: any, mergeProps?: any, options?: unknown) => InferableComponentEnhancerWithProps<{}, {}>

mapStateToProps?: any,
>mapStateToProps : any

mapDispatchToProps?: any,
>mapDispatchToProps : any

mergeProps?: any,
>mergeProps : any

options: unknown = {},
>options : unknown
>{} : {}

) {
return connect(
>connect( mapStateToProps, mapDispatchToProps, mergeProps, options, ) : InferableComponentEnhancerWithProps<{}, {}>
>connect : Connect

mapStateToProps,
>mapStateToProps : any

mapDispatchToProps,
>mapDispatchToProps : any

mergeProps,
>mergeProps : any

options,
>options : unknown

);
};
Loading

0 comments on commit 98e9b3e

Please sign in to comment.