Skip to content

Do not erase signature constraints when calculating variance #55864

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

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
@@ -22914,7 +22914,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// of the much more expensive N * M comparison matrix we explore below. We erase type parameters
// as they are known to always be the same.
for (let i = 0; i < targetSignatures.length; i++) {
const related = signatureRelatedTo(sourceSignatures[i], targetSignatures[i], /*erase*/ true, reportErrors, intersectionState, incompatibleReporter(sourceSignatures[i], targetSignatures[i]));
const related = signatureRelatedTo(sourceSignatures[i], targetSignatures[i], /*erase*/ !inVarianceComputation, reportErrors, intersectionState, incompatibleReporter(sourceSignatures[i], targetSignatures[i]));
if (!related) {
return Ternary.False;
}
4 changes: 2 additions & 2 deletions src/compiler/corePublic.ts
Original file line number Diff line number Diff line change
@@ -15,11 +15,11 @@ export interface MapLike<T> {
[index: string]: T;
}

export interface SortedReadonlyArray<T> extends ReadonlyArray<T> {
export interface SortedReadonlyArray<out T> extends ReadonlyArray<T> {
" __sortedArrayBrand": any;
}

export interface SortedArray<T> extends Array<T> {
export interface SortedArray<out T> extends Array<T> {
" __sortedArrayBrand": any;
}

4 changes: 2 additions & 2 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
@@ -1535,12 +1535,12 @@ export type HasContainerFlags =
| IsObjectLiteralOrClassExpressionMethodOrAccessor;

/** @internal */
export interface MutableNodeArray<T extends Node> extends Array<T>, TextRange {
export interface MutableNodeArray<out T extends Node> extends Array<T>, TextRange {
hasTrailingComma: boolean;
/** @internal */ transformFlags: TransformFlags; // Flags for transforms, possibly undefined
}

export interface NodeArray<T extends Node> extends ReadonlyArray<T>, ReadonlyTextRange {
export interface NodeArray<out T extends Node> extends ReadonlyArray<T>, ReadonlyTextRange {
readonly hasTrailingComma: boolean;
/** @internal */ transformFlags: TransformFlags; // Flags for transforms, possibly undefined
}
6 changes: 3 additions & 3 deletions tests/baselines/reference/api/typescript.d.ts
Original file line number Diff line number Diff line change
@@ -4145,10 +4145,10 @@ declare namespace ts {
interface MapLike<T> {
[index: string]: T;
}
interface SortedReadonlyArray<T> extends ReadonlyArray<T> {
interface SortedReadonlyArray<out T> extends ReadonlyArray<T> {
" __sortedArrayBrand": any;
}
interface SortedArray<T> extends Array<T> {
interface SortedArray<out T> extends Array<T> {
" __sortedArrayBrand": any;
}
type Path = string & {
@@ -4889,7 +4889,7 @@ declare namespace ts {
type HasExpressionInitializer = VariableDeclaration | ParameterDeclaration | BindingElement | PropertyDeclaration | PropertyAssignment | EnumMember;
type HasDecorators = ParameterDeclaration | PropertyDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | ClassExpression | ClassDeclaration;
type HasModifiers = TypeParameterDeclaration | ParameterDeclaration | ConstructorTypeNode | PropertySignature | PropertyDeclaration | MethodSignature | MethodDeclaration | ConstructorDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | IndexSignatureDeclaration | FunctionExpression | ArrowFunction | ClassExpression | VariableStatement | FunctionDeclaration | ClassDeclaration | InterfaceDeclaration | TypeAliasDeclaration | EnumDeclaration | ModuleDeclaration | ImportEqualsDeclaration | ImportDeclaration | ExportAssignment | ExportDeclaration;
interface NodeArray<T extends Node> extends ReadonlyArray<T>, ReadonlyTextRange {
interface NodeArray<out T extends Node> extends ReadonlyArray<T>, ReadonlyTextRange {
readonly hasTrailingComma: boolean;
}
interface Token<TKind extends SyntaxKind> extends Node {
19 changes: 18 additions & 1 deletion tests/baselines/reference/complexRecursiveCollections.errors.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
immutable.ts(305,22): error TS2430: Interface 'Set<T>' incorrectly extends interface 'Seq<never, T>'.
The types of 'map(...).filter(...).concat(...).toMap().toSeq().toOrderedMap().keySeq().toMap().mapKeys(...).toSeq().toOrderedMap().toSet().union' are incompatible between these types.
Type '(...collections: (never[] | Collection<any, never>)[]) => Set<never>' is not assignable to type '(...collections: (any[] | Collection<any, any>)[]) => Set<any>'.
Types of parameters 'collections' and 'collections' are incompatible.
Type 'any[] | Collection<any, any>' is not assignable to type 'never[] | Collection<any, never>'.
Type 'any[]' is not assignable to type 'never[] | Collection<any, never>'.
Type 'any[]' is not assignable to type 'never[]'.
Type 'any' is not assignable to type 'never'.
immutable.ts(341,22): error TS2430: Interface 'Keyed<K, V>' incorrectly extends interface 'Collection<K, V>'.
The types returned by 'toSeq()' are incompatible between these types.
Type 'Keyed<K, V>' is not assignable to type 'this'.
@@ -33,7 +41,7 @@ immutable.ts(391,22): error TS2430: Interface 'Set<T>' incorrectly extends inter
flatMap<M>(mapper: (value: T, key: void, iter: this) => Ara<M>, context?: any): N2<M>;
toSeq(): N2<T>;
}
==== immutable.ts (3 errors) ====
==== immutable.ts (4 errors) ====
// Test that complex recursive collections can pass the `extends` assignability check without
// running out of memory. This bug was exposed in Typescript 2.4 when more generic signatures
// started being checked.
@@ -339,6 +347,15 @@ immutable.ts(391,22): error TS2430: Interface 'Set<T>' incorrectly extends inter
export function Set<T>(): Seq.Set<T>;
export function Set<T>(collection: Iterable<T>): Seq.Set<T>;
export interface Set<T> extends Seq<never, T>, Collection.Set<T> {
~~~
!!! error TS2430: Interface 'Set<T>' incorrectly extends interface 'Seq<never, T>'.
!!! error TS2430: The types of 'map(...).filter(...).concat(...).toMap().toSeq().toOrderedMap().keySeq().toMap().mapKeys(...).toSeq().toOrderedMap().toSet().union' are incompatible between these types.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😵

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We go hard at finding the incompatibility, don't we. 😆

Guess there's an any somewhere in this type definition that should be a never (or vice-versa, depending on intent).

!!! error TS2430: Type '(...collections: (never[] | Collection<any, never>)[]) => Set<never>' is not assignable to type '(...collections: (any[] | Collection<any, any>)[]) => Set<any>'.
!!! error TS2430: Types of parameters 'collections' and 'collections' are incompatible.
!!! error TS2430: Type 'any[] | Collection<any, any>' is not assignable to type 'never[] | Collection<any, never>'.
!!! error TS2430: Type 'any[]' is not assignable to type 'never[] | Collection<any, never>'.
!!! error TS2430: Type 'any[]' is not assignable to type 'never[]'.
!!! error TS2430: Type 'any' is not assignable to type 'never'.
toJS(): Array<any>;
toJSON(): Array<T>;
toSeq(): this;
Original file line number Diff line number Diff line change
@@ -1139,7 +1139,7 @@ declare module Immutable {
>Seq : typeof Seq

function isSeq(maybeSeq: any): maybeSeq is Seq.Indexed<any> | Seq.Keyed<any, any>;
>isSeq : (maybeSeq: any) => maybeSeq is Indexed<any> | Keyed<any, any>
>isSeq : (maybeSeq: any) => maybeSeq is Keyed<any, any> | Indexed<any>
>maybeSeq : any
>Seq : any
>Seq : any
19 changes: 18 additions & 1 deletion tests/baselines/reference/conditionalTypes2.errors.txt
Original file line number Diff line number Diff line change
@@ -33,9 +33,16 @@ conditionalTypes2.ts(74,12): error TS2345: Argument of type 'Extract<T, Foo & Ba
conditionalTypes2.ts(75,12): error TS2345: Argument of type 'Extract2<T, Foo, Bar>' is not assignable to parameter of type '{ foo: string; bat: string; }'.
Type 'T extends Bar ? T : never' is not assignable to type '{ foo: string; bat: string; }'.
Property 'bat' is missing in type 'Bar & Foo' but required in type '{ foo: string; bat: string; }'.
conditionalTypes2.ts(91,5): error TS2416: Property 'tail' in type 'Vector<T>' is not assignable to the same property in base type 'Seq<T>'.
Type '() => Opt<Vector<T>>' is not assignable to type '() => Opt<Seq<T>>'.
Call signature return types 'Opt<Vector<T>>' and 'Opt<Seq<T>>' are incompatible.
The types returned by 'toVector().tail().toVector()' are incompatible between these types.
Type 'Vector<Vector<Vector<T>>>' is not assignable to type 'Vector<Vector<Seq<T>>>'.
Type 'Vector<Seq<T>>' is not assignable to type 'Vector<Vector<T>>'.
conditionalTypes2.ts(94,5): error TS2394: This overload signature is not compatible with its implementation signature.


==== conditionalTypes2.ts (7 errors) ====
==== conditionalTypes2.ts (9 errors) ====
interface Covariant<T> {
foo: T extends string ? T : number;
}
@@ -177,9 +184,19 @@ conditionalTypes2.ts(75,12): error TS2345: Argument of type 'Extract2<T, Foo, Ba

class Vector<T> implements Seq<T> {
tail(): Opt<Vector<T>> {
~~~~
!!! error TS2416: Property 'tail' in type 'Vector<T>' is not assignable to the same property in base type 'Seq<T>'.
!!! error TS2416: Type '() => Opt<Vector<T>>' is not assignable to type '() => Opt<Seq<T>>'.
!!! error TS2416: Call signature return types 'Opt<Vector<T>>' and 'Opt<Seq<T>>' are incompatible.
!!! error TS2416: The types returned by 'toVector().tail().toVector()' are incompatible between these types.
!!! error TS2416: Type 'Vector<Vector<Vector<T>>>' is not assignable to type 'Vector<Vector<Seq<T>>>'.
!!! error TS2416: Type 'Vector<Seq<T>>' is not assignable to type 'Vector<Vector<T>>'.
return <any>undefined;
}
partition2<U extends T>(predicate:(v:T)=>v is U): [Vector<U>,Vector<Exclude<T, U>>];
~~~~~~~~~~
!!! error TS2394: This overload signature is not compatible with its implementation signature.
!!! related TS2750 conditionalTypes2.ts:96:5: The implementation signature is declared here.
partition2(predicate:(x:T)=>boolean): [Vector<T>,Vector<T>];
partition2<U extends T>(predicate:(v:T)=>boolean): [Vector<U>,Vector<any>] {
return <any>undefined;
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts(9,5): error TS2322: Type 'Fn<T2>' is not assignable to type 'Fn<T1>'.
Type 'T1' is not assignable to type 'T2'.
'T2' could be instantiated with an arbitrary type which could be unrelated to 'T1'.
genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts(10,5): error TS2322: Type 'Fn<T1>' is not assignable to type 'Fn<T2>'.
Type 'T2' is not assignable to type 'T1'.
'T1' could be instantiated with an arbitrary type which could be unrelated to 'T2'.
genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts(12,5): error TS2322: Type 'Concrete2' is not assignable to type 'Concrete1'.
Types of parameters 'x' and 'x' are incompatible.
Type 'U' is not assignable to type 'string'.
Type 'number' is not assignable to type 'string'.
genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts(13,5): error TS2322: Type 'Concrete1' is not assignable to type 'Concrete2'.
Types of parameters 'x' and 'x' are incompatible.
Type 'U' is not assignable to type 'number'.
Type 'string' is not assignable to type 'number'.
genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts(15,5): error TS2322: Type 'Concrete1' is not assignable to type 'Fn<T1>'.
Types of parameters 'x' and 'x' are incompatible.
Type 'U' is not assignable to type 'number'.
Type 'T1' is not assignable to type 'number'.
genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts(16,5): error TS2322: Type 'Fn<T1>' is not assignable to type 'Concrete1'.
Types of parameters 'x' and 'x' are incompatible.
Type 'U' is not assignable to type 'T1'.
'T1' could be instantiated with an arbitrary type which could be unrelated to 'U'.


==== genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts (6 errors) ====
type Fn<T> = <U extends T>(x: U) => U;

type Concrete1 = <U extends number>(x: U) => U;
type Concrete2 = <U extends string>(x: U) => U;

function f<T1, T2>(t1: Fn<T1>, t2: Fn<T2>, c1: Concrete1, c2: Concrete2) {
// every single one of these assignments should error

t1 = t2;
~~
!!! error TS2322: Type 'Fn<T2>' is not assignable to type 'Fn<T1>'.
!!! error TS2322: Type 'T1' is not assignable to type 'T2'.
!!! error TS2322: 'T2' could be instantiated with an arbitrary type which could be unrelated to 'T1'.
!!! related TS2208 genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts:6:12: This type parameter might need an `extends T2` constraint.
t2 = t1;
~~
!!! error TS2322: Type 'Fn<T1>' is not assignable to type 'Fn<T2>'.
!!! error TS2322: Type 'T2' is not assignable to type 'T1'.
!!! error TS2322: 'T1' could be instantiated with an arbitrary type which could be unrelated to 'T2'.
!!! related TS2208 genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts:6:16: This type parameter might need an `extends T1` constraint.

c1 = c2;
~~
!!! error TS2322: Type 'Concrete2' is not assignable to type 'Concrete1'.
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
!!! error TS2322: Type 'U' is not assignable to type 'string'.
!!! error TS2322: Type 'number' is not assignable to type 'string'.
c2 = c1;
~~
!!! error TS2322: Type 'Concrete1' is not assignable to type 'Concrete2'.
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
!!! error TS2322: Type 'U' is not assignable to type 'number'.
!!! error TS2322: Type 'string' is not assignable to type 'number'.

t1 = c1;
~~
!!! error TS2322: Type 'Concrete1' is not assignable to type 'Fn<T1>'.
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
!!! error TS2322: Type 'U' is not assignable to type 'number'.
!!! error TS2322: Type 'T1' is not assignable to type 'number'.
!!! related TS2208 genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts:6:12: This type parameter might need an `extends number` constraint.
c1 = t1;
~~
!!! error TS2322: Type 'Fn<T1>' is not assignable to type 'Concrete1'.
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
!!! error TS2322: Type 'U' is not assignable to type 'T1'.
!!! error TS2322: 'T1' could be instantiated with an arbitrary type which could be unrelated to 'U'.
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//// [tests/cases/compiler/genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts] ////

//// [genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts]
type Fn<T> = <U extends T>(x: U) => U;

type Concrete1 = <U extends number>(x: U) => U;
type Concrete2 = <U extends string>(x: U) => U;

function f<T1, T2>(t1: Fn<T1>, t2: Fn<T2>, c1: Concrete1, c2: Concrete2) {
// every single one of these assignments should error

t1 = t2;
t2 = t1;

c1 = c2;
c2 = c1;

t1 = c1;
c1 = t1;
}


//// [genericSignaturesConstrainedToDifferingGenericsNotCompatible.js]
"use strict";
function f(t1, t2, c1, c2) {
// every single one of these assignments should error
t1 = t2;
t2 = t1;
c1 = c2;
c2 = c1;
t1 = c1;
c1 = t1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//// [tests/cases/compiler/genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts] ////

=== genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts ===
type Fn<T> = <U extends T>(x: U) => U;
>Fn : Symbol(Fn, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 0, 0))
>T : Symbol(T, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 0, 8))
>U : Symbol(U, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 0, 14))
>T : Symbol(T, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 0, 8))
>x : Symbol(x, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 0, 27))
>U : Symbol(U, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 0, 14))
>U : Symbol(U, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 0, 14))

type Concrete1 = <U extends number>(x: U) => U;
>Concrete1 : Symbol(Concrete1, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 0, 38))
>U : Symbol(U, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 2, 18))
>x : Symbol(x, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 2, 36))
>U : Symbol(U, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 2, 18))
>U : Symbol(U, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 2, 18))

type Concrete2 = <U extends string>(x: U) => U;
>Concrete2 : Symbol(Concrete2, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 2, 47))
>U : Symbol(U, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 3, 18))
>x : Symbol(x, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 3, 36))
>U : Symbol(U, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 3, 18))
>U : Symbol(U, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 3, 18))

function f<T1, T2>(t1: Fn<T1>, t2: Fn<T2>, c1: Concrete1, c2: Concrete2) {
>f : Symbol(f, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 3, 47))
>T1 : Symbol(T1, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 11))
>T2 : Symbol(T2, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 14))
>t1 : Symbol(t1, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 19))
>Fn : Symbol(Fn, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 0, 0))
>T1 : Symbol(T1, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 11))
>t2 : Symbol(t2, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 30))
>Fn : Symbol(Fn, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 0, 0))
>T2 : Symbol(T2, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 14))
>c1 : Symbol(c1, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 42))
>Concrete1 : Symbol(Concrete1, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 0, 38))
>c2 : Symbol(c2, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 57))
>Concrete2 : Symbol(Concrete2, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 2, 47))

// every single one of these assignments should error

t1 = t2;
>t1 : Symbol(t1, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 19))
>t2 : Symbol(t2, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 30))

t2 = t1;
>t2 : Symbol(t2, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 30))
>t1 : Symbol(t1, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 19))

c1 = c2;
>c1 : Symbol(c1, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 42))
>c2 : Symbol(c2, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 57))

c2 = c1;
>c2 : Symbol(c2, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 57))
>c1 : Symbol(c1, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 42))

t1 = c1;
>t1 : Symbol(t1, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 19))
>c1 : Symbol(c1, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 42))

c1 = t1;
>c1 : Symbol(c1, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 42))
>t1 : Symbol(t1, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 19))
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//// [tests/cases/compiler/genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts] ////

=== genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts ===
type Fn<T> = <U extends T>(x: U) => U;
>Fn : Fn<T>
>x : U

type Concrete1 = <U extends number>(x: U) => U;
>Concrete1 : <U extends number>(x: U) => U
>x : U

type Concrete2 = <U extends string>(x: U) => U;
>Concrete2 : <U extends string>(x: U) => U
>x : U

function f<T1, T2>(t1: Fn<T1>, t2: Fn<T2>, c1: Concrete1, c2: Concrete2) {
>f : <T1, T2>(t1: Fn<T1>, t2: Fn<T2>, c1: Concrete1, c2: Concrete2) => void
>t1 : Fn<T1>
>t2 : Fn<T2>
>c1 : Concrete1
>c2 : Concrete2

// every single one of these assignments should error

t1 = t2;
>t1 = t2 : Fn<T2>
>t1 : Fn<T1>
>t2 : Fn<T2>

t2 = t1;
>t2 = t1 : Fn<T1>
>t2 : Fn<T2>
>t1 : Fn<T1>

c1 = c2;
>c1 = c2 : Concrete2
>c1 : Concrete1
>c2 : Concrete2

c2 = c1;
>c2 = c1 : Concrete1
>c2 : Concrete2
>c1 : Concrete1

t1 = c1;
>t1 = c1 : Concrete1
>t1 : Fn<T1>
>c1 : Concrete1

c1 = t1;
>c1 = t1 : Fn<T1>
>c1 : Concrete1
>t1 : Fn<T1>
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
styledComponentsInstantiaionLimitNotReached.ts(171,8): error TS2615: Type of property 'propTypes' circularly references itself in mapped type 'ForwardRefExoticBase<Omit<Omit<any, any> & Partial<Pick<any, any>>, "theme"> & { theme?: any; } & WithChildrenIfReactComponentClass<StyledComponentInnerComponent<WithC>>>'.


==== styledComponentsInstantiaionLimitNotReached.ts (1 errors) ====
/// <reference path="/.lib/react16.d.ts" />
import * as React from "react";

interface REACT_STATICS {
childContextTypes: true;
contextType: true;
contextTypes: true;
defaultProps: true;
displayName: true;
getDefaultProps: true;
getDerivedStateFromError: true;
getDerivedStateFromProps: true;
mixins: true;
propTypes: true;
type: true;
}

interface KNOWN_STATICS {
name: true;
length: true;
prototype: true;
caller: true;
callee: true;
arguments: true;
arity: true;
}

interface MEMO_STATICS {
'$$typeof': true;
compare: true;
defaultProps: true;
displayName: true;
propTypes: true;
type: true;
}

interface FORWARD_REF_STATICS {
'$$typeof': true;
render: true;
defaultProps: true;
displayName: true;
propTypes: true;
}


type NonReactStatics<
S extends React.ComponentType<any>,
C extends {
[key: string]: true
} = {}
> = {
[key in Exclude<
keyof S,
S extends React.MemoExoticComponent<any>
? keyof MEMO_STATICS | keyof C
: S extends React.ForwardRefExoticComponent<any>
? keyof FORWARD_REF_STATICS | keyof C
: keyof REACT_STATICS | keyof KNOWN_STATICS | keyof C
>]: S[key]
};

export type AnyStyledComponent = StyledComponent<any, any, any, any> | StyledComponent<any, any, any>;
export type StyledComponent<
C extends keyof JSX.IntrinsicElements | React.ComponentType<any>,
T extends object,
O extends object = {},
A extends keyof any = never
> = // the "string" allows this to be used as an object key
// I really want to avoid this if possible but it's the only way to use nesting with object styles...
string &
StyledComponentBase<C, T, O, A> &
NonReactStatics<C extends React.ComponentType<any> ? C : never>;

export type StyledComponentProps<
// The Component from whose props are derived
C extends string | React.ComponentType<any>,
// The Theme from the current context
T extends object,
// The other props added by the template
O extends object,
// The props that are made optional by .attrs
A extends keyof any
> =
// Distribute O if O is a union type
O extends object
? WithOptionalTheme<
Omit<
ReactDefaultizedProps<
C,
React.ComponentPropsWithRef<
C extends IntrinsicElementsKeys | React.ComponentType<any> ? C : never
>
> &
O,
A
> &
Partial<
Pick<
React.ComponentPropsWithRef<
C extends IntrinsicElementsKeys | React.ComponentType<any> ? C : never
> &
O,
A
>
>,
T
> &
WithChildrenIfReactComponentClass<C>
: never;

type Defaultize<P, D> = P extends any
? string extends keyof P
? P
: Pick<P, Exclude<keyof P, keyof D>> &
Partial<Pick<P, Extract<keyof P, keyof D>>> &
Partial<Pick<D, Exclude<keyof D, keyof P>>>
: never;

type ReactDefaultizedProps<C, P> = C extends { defaultProps: infer D } ? Defaultize<P, D> : P;

type WithChildrenIfReactComponentClass<C extends string | React.ComponentType<any>> = C extends React.ComponentClass<
any
>
? { children?: React.ReactNode }
: {};
export type IntrinsicElementsKeys = keyof JSX.IntrinsicElements;
type WithOptionalTheme<P extends { theme?: T }, T> = Omit<P, 'theme'> & {
theme?: T;
};

type ForwardRefExoticBase<P> = Pick<React.ForwardRefExoticComponent<P>, keyof React.ForwardRefExoticComponent<any>>;

type StyledComponentPropsWithAs<
C extends string | React.ComponentType<any>,
T extends object,
O extends object,
A extends keyof any,
F extends string | React.ComponentType<any> = C
> = StyledComponentProps<C, T, O, A> & { as?: C; forwardedAs?: F };

export type StyledComponentInnerOtherProps<C extends AnyStyledComponent> = C extends StyledComponent<
any,
any,
infer O,
any
>
? O
: C extends StyledComponent<any, any, infer O>
? O
: never;
export type StyledComponentInnerAttrs<C extends AnyStyledComponent> = C extends StyledComponent<any, any, any, infer A>
? A
: never;

export interface StyledComponentBase<
C extends string | React.ComponentType<any>,
T extends object,
O extends object = {},
A extends keyof any = never
> extends ForwardRefExoticBase<StyledComponentProps<C, T, O, A>> {
// add our own fake call signature to implement the polymorphic 'as' prop
(props: StyledComponentProps<C, T, O, A> & { as?: never; forwardedAs?: never }): React.ReactElement<
StyledComponentProps<C, T, O, A>
>;
<AsC extends string | React.ComponentType<any> = C, FAsC extends string | React.ComponentType<any> = AsC>(
props: StyledComponentPropsWithAs<AsC, T, O, A, FAsC>,
): React.ReactElement<StyledComponentPropsWithAs<AsC, T, O, A, FAsC>>;

withComponent<WithC extends AnyStyledComponent>(
component: WithC,
): StyledComponent<
~~~~~~~~~~~~~~~~
StyledComponentInnerComponent<WithC>,
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
T,
~~~~~~~~~~
O & StyledComponentInnerOtherProps<WithC>,
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A | StyledComponentInnerAttrs<WithC>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>;
~~~~~
!!! error TS2615: Type of property 'propTypes' circularly references itself in mapped type 'ForwardRefExoticBase<Omit<Omit<any, any> & Partial<Pick<any, any>>, "theme"> & { theme?: any; } & WithChildrenIfReactComponentClass<StyledComponentInnerComponent<WithC>>>'.
withComponent<WithC extends keyof JSX.IntrinsicElements | React.ComponentType<any>>(
component: WithC,
): StyledComponent<WithC, T, O, A>;
}

export type StyledComponentInnerComponent<C extends React.ComponentType<any>> = C extends StyledComponent<
infer I,
any,
any,
any
>
? I
: C extends StyledComponent<infer I, any, any>
? I
: C;
export type StyledComponentPropsWithRef<
C extends keyof JSX.IntrinsicElements | React.ComponentType<any>
> = C extends AnyStyledComponent
? React.ComponentPropsWithRef<StyledComponentInnerComponent<C>> // shouldn't have an instantiation limit error
: React.ComponentPropsWithRef<C>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// @strict: true
type Fn<T> = <U extends T>(x: U) => U;

type Concrete1 = <U extends number>(x: U) => U;
type Concrete2 = <U extends string>(x: U) => U;

function f<T1, T2>(t1: Fn<T1>, t2: Fn<T2>, c1: Concrete1, c2: Concrete2) {
// every single one of these assignments should error

t1 = t2;
t2 = t1;

c1 = c2;
c2 = c1;

t1 = c1;
c1 = t1;
}