Skip to content

Do not measure variance for a conditional type extendsType #31277

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

Closed
Show file tree
Hide file tree
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
3 changes: 2 additions & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18545,8 +18545,9 @@ namespace ts {
// Two conditional types 'T1 extends U1 ? X1 : Y1' and 'T2 extends U2 ? X2 : Y2' are related if
// one of T1 and T2 is related to the other, U1 and U2 are identical types, X1 is related to X2,
// and Y1 is related to Y2.

const sourceParams = (source as ConditionalType).root.inferTypeParameters;
let sourceExtends = (<ConditionalType>source).extendsType;
let sourceExtends = instantiateType((<ConditionalType>source).extendsType, makeFunctionTypeMapper(reportUnmeasurableMarkers));
let mapper: TypeMapper | undefined;
if (sourceParams) {
// If the source has infer type parameters, we instantiate them in the context of the target
Expand Down
52 changes: 52 additions & 0 deletions tests/baselines/reference/variance.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,48 @@ class Bar<T extends string> {
Bar.instance.push(this);
}
}



interface Set<T> {
add(value: T): this;
}

declare const Set: new <T>() => Set<T>;

// Repro from #31251 (removed getter)

export abstract class Supervisor<N extends string, P = unknown, R = unknown> {
private static instances_: Set<Supervisor<string, unknown, unknown>>;
private static instances(): typeof Supervisor.instances_ {
return this.hasOwnProperty('instances_')
? this.instances_
: this.instances_ = new Set();
}
constructor() {
void (this.constructor as typeof Supervisor).instances().add(this);
}
public abstract call(name: N | ('' extends N ? undefined : never), param: P, timeout?: number): Promise<R>;
}


// Minimal repro for catching variance probing in then extends type.

interface A<T> {
x: number extends T ? 1 : 1;
}

declare let a: A<number>;
declare let b: A<3>;

a = b; // error
b = a; // error


//// [variance.js]
"use strict";
// Test cases for parameter variances affected by conditional types.
exports.__esModule = true;
var foo = { prop: true };
var x = foo;
var y = foo;
Expand All @@ -43,3 +80,18 @@ var Bar = /** @class */ (function () {
};
return Bar;
}());
// Repro from #31251 (removed getter)
var Supervisor = /** @class */ (function () {
function Supervisor() {
void this.constructor.instances().add(this);
}
Supervisor.instances = function () {
return this.hasOwnProperty('instances_')
? this.instances_
: this.instances_ = new Set();
};
return Supervisor;
}());
exports.Supervisor = Supervisor;
a = b; // error
b = a; // error
105 changes: 105 additions & 0 deletions tests/baselines/reference/variance.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,108 @@ class Bar<T extends string> {
}
}



interface Set<T> {
>Set : Symbol(Set, Decl(variance.ts, 24, 1), Decl(variance.ts, 32, 13))
>T : Symbol(T, Decl(variance.ts, 28, 14))

add(value: T): this;
>add : Symbol(Set.add, Decl(variance.ts, 28, 18))
>value : Symbol(value, Decl(variance.ts, 29, 8))
>T : Symbol(T, Decl(variance.ts, 28, 14))
}

declare const Set: new <T>() => Set<T>;
>Set : Symbol(Set, Decl(variance.ts, 24, 1), Decl(variance.ts, 32, 13))
>T : Symbol(T, Decl(variance.ts, 32, 24))
>Set : Symbol(Set, Decl(variance.ts, 24, 1), Decl(variance.ts, 32, 13))
>T : Symbol(T, Decl(variance.ts, 32, 24))

// Repro from #31251 (removed getter)

export abstract class Supervisor<N extends string, P = unknown, R = unknown> {
>Supervisor : Symbol(Supervisor, Decl(variance.ts, 32, 39))
>N : Symbol(N, Decl(variance.ts, 36, 33))
>P : Symbol(P, Decl(variance.ts, 36, 50))
>R : Symbol(R, Decl(variance.ts, 36, 63))

private static instances_: Set<Supervisor<string, unknown, unknown>>;
>instances_ : Symbol(Supervisor.instances_, Decl(variance.ts, 36, 78))
>Set : Symbol(Set, Decl(variance.ts, 24, 1), Decl(variance.ts, 32, 13))
>Supervisor : Symbol(Supervisor, Decl(variance.ts, 32, 39))

private static instances(): typeof Supervisor.instances_ {
>instances : Symbol(Supervisor.instances, Decl(variance.ts, 37, 73))
>Supervisor.instances_ : Symbol(Supervisor.instances_, Decl(variance.ts, 36, 78))
>Supervisor : Symbol(Supervisor, Decl(variance.ts, 32, 39))
>instances_ : Symbol(Supervisor.instances_, Decl(variance.ts, 36, 78))

return this.hasOwnProperty('instances_')
>this.hasOwnProperty : Symbol(Object.hasOwnProperty, Decl(lib.es5.d.ts, --, --))
>this : Symbol(Supervisor, Decl(variance.ts, 32, 39))
>hasOwnProperty : Symbol(Object.hasOwnProperty, Decl(lib.es5.d.ts, --, --))

? this.instances_
>this.instances_ : Symbol(Supervisor.instances_, Decl(variance.ts, 36, 78))
>this : Symbol(Supervisor, Decl(variance.ts, 32, 39))
>instances_ : Symbol(Supervisor.instances_, Decl(variance.ts, 36, 78))

: this.instances_ = new Set();
>this.instances_ : Symbol(Supervisor.instances_, Decl(variance.ts, 36, 78))
>this : Symbol(Supervisor, Decl(variance.ts, 32, 39))
>instances_ : Symbol(Supervisor.instances_, Decl(variance.ts, 36, 78))
>Set : Symbol(Set, Decl(variance.ts, 24, 1), Decl(variance.ts, 32, 13))
}
constructor() {
void (this.constructor as typeof Supervisor).instances().add(this);
>(this.constructor as typeof Supervisor).instances().add : Symbol(Set.add, Decl(variance.ts, 28, 18))
>(this.constructor as typeof Supervisor).instances : Symbol(Supervisor.instances, Decl(variance.ts, 37, 73))
>this.constructor : Symbol(Object.constructor, Decl(lib.es5.d.ts, --, --))
>this : Symbol(Supervisor, Decl(variance.ts, 32, 39))
>constructor : Symbol(Object.constructor, Decl(lib.es5.d.ts, --, --))
>Supervisor : Symbol(Supervisor, Decl(variance.ts, 32, 39))
>instances : Symbol(Supervisor.instances, Decl(variance.ts, 37, 73))
>add : Symbol(Set.add, Decl(variance.ts, 28, 18))
>this : Symbol(Supervisor, Decl(variance.ts, 32, 39))
}
public abstract call(name: N | ('' extends N ? undefined : never), param: P, timeout?: number): Promise<R>;
>call : Symbol(Supervisor.call, Decl(variance.ts, 45, 5))
>name : Symbol(name, Decl(variance.ts, 46, 25))
>N : Symbol(N, Decl(variance.ts, 36, 33))
>N : Symbol(N, Decl(variance.ts, 36, 33))
>param : Symbol(param, Decl(variance.ts, 46, 70))
>P : Symbol(P, Decl(variance.ts, 36, 50))
>timeout : Symbol(timeout, Decl(variance.ts, 46, 80))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --))
>R : Symbol(R, Decl(variance.ts, 36, 63))
}


// Minimal repro for catching variance probing in then extends type.

interface A<T> {
>A : Symbol(A, Decl(variance.ts, 47, 1))
>T : Symbol(T, Decl(variance.ts, 52, 12))

x: number extends T ? 1 : 1;
>x : Symbol(A.x, Decl(variance.ts, 52, 16))
>T : Symbol(T, Decl(variance.ts, 52, 12))
}

declare let a: A<number>;
>a : Symbol(a, Decl(variance.ts, 56, 11))
>A : Symbol(A, Decl(variance.ts, 47, 1))

declare let b: A<3>;
>b : Symbol(b, Decl(variance.ts, 57, 11))
>A : Symbol(A, Decl(variance.ts, 47, 1))

a = b; // error
>a : Symbol(a, Decl(variance.ts, 56, 11))
>b : Symbol(b, Decl(variance.ts, 57, 11))

b = a; // error
>b : Symbol(b, Decl(variance.ts, 57, 11))
>a : Symbol(a, Decl(variance.ts, 56, 11))

94 changes: 94 additions & 0 deletions tests/baselines/reference/variance.types
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,97 @@ class Bar<T extends string> {
}
}



interface Set<T> {
add(value: T): this;
>add : (value: T) => this
>value : T
}

declare const Set: new <T>() => Set<T>;
>Set : new <T>() => Set<T>

// Repro from #31251 (removed getter)

export abstract class Supervisor<N extends string, P = unknown, R = unknown> {
>Supervisor : Supervisor<N, P, R>

private static instances_: Set<Supervisor<string, unknown, unknown>>;
>instances_ : Set<Supervisor<string, unknown, unknown>>

private static instances(): typeof Supervisor.instances_ {
>instances : () => Set<Supervisor<string, unknown, unknown>>
>Supervisor.instances_ : Set<Supervisor<string, unknown, unknown>>
>Supervisor : typeof Supervisor
>instances_ : Set<Supervisor<string, unknown, unknown>>

return this.hasOwnProperty('instances_')
>this.hasOwnProperty('instances_') ? this.instances_ : this.instances_ = new Set() : Set<Supervisor<string, unknown, unknown>>
>this.hasOwnProperty('instances_') : boolean
>this.hasOwnProperty : (v: string | number | symbol) => boolean
>this : typeof Supervisor
>hasOwnProperty : (v: string | number | symbol) => boolean
>'instances_' : "instances_"

? this.instances_
>this.instances_ : Set<Supervisor<string, unknown, unknown>>
>this : typeof Supervisor
>instances_ : Set<Supervisor<string, unknown, unknown>>

: this.instances_ = new Set();
>this.instances_ = new Set() : Set<Supervisor<string, unknown, unknown>>
>this.instances_ : Set<Supervisor<string, unknown, unknown>>
>this : typeof Supervisor
>instances_ : Set<Supervisor<string, unknown, unknown>>
>new Set() : Set<Supervisor<string, unknown, unknown>>
>Set : new <T>() => Set<T>
}
constructor() {
void (this.constructor as typeof Supervisor).instances().add(this);
>void (this.constructor as typeof Supervisor).instances().add(this) : undefined
>(this.constructor as typeof Supervisor).instances().add(this) : Set<Supervisor<string, unknown, unknown>>
>(this.constructor as typeof Supervisor).instances().add : (value: Supervisor<string, unknown, unknown>) => Set<Supervisor<string, unknown, unknown>>
>(this.constructor as typeof Supervisor).instances() : Set<Supervisor<string, unknown, unknown>>
>(this.constructor as typeof Supervisor).instances : () => Set<Supervisor<string, unknown, unknown>>
>(this.constructor as typeof Supervisor) : typeof Supervisor
>this.constructor as typeof Supervisor : typeof Supervisor
>this.constructor : Function
>this : this
>constructor : Function
>Supervisor : typeof Supervisor
>instances : () => Set<Supervisor<string, unknown, unknown>>
>add : (value: Supervisor<string, unknown, unknown>) => Set<Supervisor<string, unknown, unknown>>
>this : this
}
public abstract call(name: N | ('' extends N ? undefined : never), param: P, timeout?: number): Promise<R>;
>call : (name: N | ("" extends N ? undefined : never), param: P, timeout?: number | undefined) => Promise<R>
>name : N | ("" extends N ? undefined : never)
>param : P
>timeout : number | undefined
}


// Minimal repro for catching variance probing in then extends type.

interface A<T> {
x: number extends T ? 1 : 1;
>x : number extends T ? 1 : 1
}

declare let a: A<number>;
>a : A<number>

declare let b: A<3>;
>b : A<3>

a = b; // error
>a = b : A<3>
>a : A<number>
>b : A<3>

b = a; // error
>b = a : A<number>
>b : A<3>
>a : A<number>

36 changes: 36 additions & 0 deletions tests/cases/conformance/types/conditional/variance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,39 @@ class Bar<T extends string> {
Bar.instance.push(this);
}
}



interface Set<T> {
add(value: T): this;
}

declare const Set: new <T>() => Set<T>;

// Repro from #31251 (removed getter)

export abstract class Supervisor<N extends string, P = unknown, R = unknown> {
private static instances_: Set<Supervisor<string, unknown, unknown>>;
private static instances(): typeof Supervisor.instances_ {
return this.hasOwnProperty('instances_')
? this.instances_
: this.instances_ = new Set();
}
constructor() {
void (this.constructor as typeof Supervisor).instances().add(this);
}
public abstract call(name: N | ('' extends N ? undefined : never), param: P, timeout?: number): Promise<R>;
}


// Minimal repro for catching variance probing in then extends type.

interface A<T> {
x: number extends T ? 1 : 1;
}

declare let a: A<number>;
declare let b: A<3>;

a = b; // error
b = a; // error