Skip to content

Type comparison when conditional type is target #35741

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
wants to merge 2 commits into from
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
129 changes: 72 additions & 57 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4737,7 +4737,9 @@ namespace ts {
/* @internal */
resolvedInferredTrueType?: Type; // The `trueType` instantiated with the `combinedMapper`, if present
/* @internal */
resolvedDefaultConstraint?: Type;
resolvedDefaultConstraintForReading?: Type;
/* @internal */
resolvedDefaultConstraintForWriting?: Type;
/* @internal */
mapper?: TypeMapper;
/* @internal */
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
tests/cases/compiler/conditionalTypeAssignabilityWhenDeferred.ts(14,22): error TS2345: Argument of type '"value"' is not assignable to parameter of type 'XX extends XX ? "value" : never'.
Type '"value"' is not assignable to type 'never'.
tests/cases/compiler/conditionalTypeAssignabilityWhenDeferred.ts(32,20): error TS2345: Argument of type 'string' is not assignable to parameter of type 'never'.
tests/cases/compiler/conditionalTypeAssignabilityWhenDeferred.ts(33,21): error TS2345: Argument of type 'string' is not assignable to parameter of type 'never'.
tests/cases/compiler/conditionalTypeAssignabilityWhenDeferred.ts(37,24): error TS2345: Argument of type 'T | null' is not assignable to parameter of type 'null extends T | null ? any : never'.
Type 'null' is not assignable to type 'null extends T | null ? any : never'.
Type 'null' is not assignable to type 'never'.
tests/cases/compiler/conditionalTypeAssignabilityWhenDeferred.ts(43,5): error TS2322: Type '{ x: T; y: T; }' is not assignable to type 'T extends T ? { x: T; y: T; } : never'.
Type '{ x: T; y: T; }' is not assignable to type 'never'.
tests/cases/compiler/conditionalTypeAssignabilityWhenDeferred.ts(50,5): error TS2322: Type 'string' is not assignable to type 'Foo<T>'.
Type 'string' is not assignable to type '"a"'.
tests/cases/compiler/conditionalTypeAssignabilityWhenDeferred.ts(111,5): error TS2322: Type 'Q' is not assignable to type 'InferBecauseWhyNot<Q>'.
Type '(arg: any) => any' is not assignable to type 'InferBecauseWhyNot<Q>'.
Type '(arg: any) => any' is not assignable to type 'never'.
Type 'Q' is not assignable to type 'never'.
Type '(arg: any) => any' is not assignable to type 'never'.
tests/cases/compiler/conditionalTypeAssignabilityWhenDeferred.ts(131,1): error TS2322: Type 'true' is not assignable to type 'false'.
tests/cases/compiler/conditionalTypeAssignabilityWhenDeferred.ts(132,1): error TS2322: Type 'false' is not assignable to type 'true'.
tests/cases/compiler/conditionalTypeAssignabilityWhenDeferred.ts(136,1): error TS2322: Type 'false' is not assignable to type 'true'.
tests/cases/compiler/conditionalTypeAssignabilityWhenDeferred.ts(137,1): error TS2322: Type 'true' is not assignable to type 'false'.
tests/cases/compiler/conditionalTypeAssignabilityWhenDeferred.ts(147,5): error TS2322: Type 'T extends "a" ? true : false' is not assignable to type 'false'.
Type 'boolean' is not assignable to type 'false'.
Type 'true' is not assignable to type 'false'.
tests/cases/compiler/conditionalTypeAssignabilityWhenDeferred.ts(148,5): error TS2322: Type 'T extends "b" ? true : false' is not assignable to type 'true'.
Type 'boolean' is not assignable to type 'true'.
Type 'false' is not assignable to type 'true'.
tests/cases/compiler/conditionalTypeAssignabilityWhenDeferred.ts(152,5): error TS2322: Type 'false' is not assignable to type 'T extends "a" ? true : false'.
Type 'false' is not assignable to type 'never'.
Type 'false' is not assignable to type 'true'.
tests/cases/compiler/conditionalTypeAssignabilityWhenDeferred.ts(153,5): error TS2322: Type 'true' is not assignable to type 'T extends "b" ? true : false'.
Type 'true' is not assignable to type 'never'.
Type 'true' is not assignable to type 'false'.


==== tests/cases/compiler/conditionalTypeAssignabilityWhenDeferred.ts (15 errors) ====
// #29505

export type FilterPropsByType<T, TT> = {
[K in keyof T]: T[K] extends TT ? K : never
}[keyof T];

function select<
T extends string | number,
TList extends object,
TValueProp extends FilterPropsByType<TList, T>
>(property: T, list: TList[], valueProp: TValueProp) {}

<XX extends string>(x: XX, tipos: { value: XX }[]) => {
select(x, tipos, "value");
~~~~~~~
!!! error TS2345: Argument of type '"value"' is not assignable to parameter of type 'XX extends XX ? "value" : never'.
!!! error TS2345: Type '"value"' is not assignable to type 'never'.
};

// #29662

declare function onlyNullablePlease<T extends null extends T ? any : never>(
value: T
): void;

declare function onlyNullablePlease2<
T extends [null] extends [T] ? any : never
>(value: T): void;

declare var z: string | null;
onlyNullablePlease(z); // works as expected
onlyNullablePlease2(z); // works as expected

declare var y: string;
onlyNullablePlease(y); // error as expected
~
!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'never'.
onlyNullablePlease2(y); // error as expected
~
!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'never'.

<T>(t: T) => {
var x: T | null = Math.random() > 0.5 ? null : t;
onlyNullablePlease(x); // should work
~
!!! error TS2345: Argument of type 'T | null' is not assignable to parameter of type 'null extends T | null ? any : never'.
!!! error TS2345: Type 'null' is not assignable to type 'null extends T | null ? any : never'.
!!! error TS2345: Type 'null' is not assignable to type 'never'.
onlyNullablePlease2(x); // should work
};

<T>(t1: { x: T; y: T }, t2: T extends T ? { x: T; y: T } : never) => {
t1 = t2; // OK
t2 = t1; // should fail
~~
!!! error TS2322: Type '{ x: T; y: T; }' is not assignable to type 'T extends T ? { x: T; y: T; } : never'.
!!! error TS2322: Type '{ x: T; y: T; }' is not assignable to type 'never'.
};

type Foo<T> = T extends true ? string : "a";

<T>(x: Foo<T>, s: string) => {
x = "a"; // Currently an error, should be ok
x = s; // Error
~
!!! error TS2322: Type 'string' is not assignable to type 'Foo<T>'.
!!! error TS2322: Type 'string' is not assignable to type '"a"'.
};

// #26933

type Distributive<T> = T extends { a: number } ? { a: number } : { b: number };
<T>() => {
const o = { a: 1, b: 2 };
const x: [T] extends [string]
? { y: number }
: { a: number; b: number } = undefined!;
// Simple case: OK
const o1: [T] extends [number] ? { a: number } : { b: number } = o;
// Simple case where source happens to be a conditional type: also OK
const x1: [T] extends [number]
? ([T] extends [string] ? { y: number } : { a: number })
: ([T] extends [string] ? { y: number } : { b: number }) = x;
// Infer type parameters: no good
const o2: [T] extends [[infer U]] ? U : { b: number } = o;

// The next 4 are arguable - if you choose to ignore the `never` distribution case,
// then they're all good. The `never` case _is_ a bit of an outlier - we say distributive types
// look approximately like the sum of their branches, but the `never` case bucks that.
// There's an argument for the result of dumping `never` into a distributive conditional
// being not `never`, but instead the intersection of the branches - a much more precise bound
// on that "impossible" input.

// Distributive where T might instantiate to never: no good
const o3: Distributive<T> = o;
// Distributive where T & string might instantiate to never: also no good
const o4: Distributive<T & string> = o;
// Distributive where {a: T} cannot instantiate to never: OK
const o5: Distributive<{ a: T }> = o;
// Distributive where check type is a conditional which returns a non-never type upon instantiation with `never` but can still return never otherwise: no good
const o6: Distributive<[T] extends [never] ? { a: number } : never> = o;
};

type Wrapped<T> = { ___secret: T };
type Unwrap<T> = T extends Wrapped<infer U> ? U : T;

declare function set<T, K extends keyof T>(
obj: T,
key: K,
value: Unwrap<T[K]>
): Unwrap<T[K]>;

class Foo2 {
prop!: Wrapped<string>;

method() {
set(this, "prop", "hi"); // <-- type error
}
}

set(new Foo2(), "prop", "hi"); // <-- typechecks

type InferBecauseWhyNot<T> = [T] extends [(p: infer P1) => any]
? P1 | T
: never;

<Q extends (arg: any) => any>(x: Q): InferBecauseWhyNot<Q> => {
return x;
~~~~~~~~~
!!! error TS2322: Type 'Q' is not assignable to type 'InferBecauseWhyNot<Q>'.
!!! error TS2322: Type '(arg: any) => any' is not assignable to type 'InferBecauseWhyNot<Q>'.
!!! error TS2322: Type '(arg: any) => any' is not assignable to type 'never'.
!!! error TS2322: Type 'Q' is not assignable to type 'never'.
!!! error TS2322: Type '(arg: any) => any' is not assignable to type 'never'.
};

type InferBecauseWhyNotDistributive<T> = T extends (p: infer P1) => any
? P1 | T
: never;

<Q extends (arg: any) => any>(
x: Q
): InferBecauseWhyNotDistributive<Q> => {
return x; // should fail
};

let t: true;
let f: false;

let a: "a" extends "a" ? true : false = undefined!;
let b: "a" extends "b" ? true : false = undefined!;

t = a;
f = a; // !!! error TS2322: Type 'true' is not assignable to type 'false'.
~
!!! error TS2322: Type 'true' is not assignable to type 'false'.
t = b; // !!! error TS2322: Type 'false' is not assignable to type 'true'.
~
!!! error TS2322: Type 'false' is not assignable to type 'true'.
f = b;

a = true;
a = false; // !!! error TS2322: Type 'false' is not assignable to type 'true'.
~
!!! error TS2322: Type 'false' is not assignable to type 'true'.
b = true; // !!! error TS2322: Type 'true' is not assignable to type 'false'.
~
!!! error TS2322: Type 'true' is not assignable to type 'false'.
b = false;

// #23132

<T extends "a">() => {
let a: T extends "a" ? true : false = undefined!;
let b: T extends "b" ? true : false = undefined!;

t = a;
f = a; // !!! error TS2322: Type 'T extends "a" ? true : false' is not assignable to type 'false'.
~
!!! error TS2322: Type 'T extends "a" ? true : false' is not assignable to type 'false'.
!!! error TS2322: Type 'boolean' is not assignable to type 'false'.
!!! error TS2322: Type 'true' is not assignable to type 'false'.
t = b; // !!! error TS2322: Type 'T extends "b" ? true : false' is not assignable to type 'true'.
~
!!! error TS2322: Type 'T extends "b" ? true : false' is not assignable to type 'true'.
!!! error TS2322: Type 'boolean' is not assignable to type 'true'.
!!! error TS2322: Type 'false' is not assignable to type 'true'.
f = b;

a = true;
a = false; // !!! error TS2322: Type 'false' is not assignable to type 'T extends "a" ? true : false'.
~
!!! error TS2322: Type 'false' is not assignable to type 'T extends "a" ? true : false'.
!!! error TS2322: Type 'false' is not assignable to type 'never'.
!!! error TS2322: Type 'false' is not assignable to type 'true'.
b = true; // !!! error TS2322: Type 'true' is not assignable to type 'T extends "b" ? true : false'.
~
!!! error TS2322: Type 'true' is not assignable to type 'T extends "b" ? true : false'.
!!! error TS2322: Type 'true' is not assignable to type 'never'.
!!! error TS2322: Type 'true' is not assignable to type 'false'.
b = false;
};

Loading