mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-06-17 21:09:09 -05:00
allow extends type to be supertype of constraint types
This commit is contained in:
@@ -46082,7 +46082,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
// (0) The conditional type is distributive;
|
||||
// (1) The conditional type has no `infer` type parameters;
|
||||
// (2) The conditional type's check type is a narrowable type parameter (i.e. a type parameter with a union constraint);
|
||||
// (3) The extends type `A` is a type or a union of types belonging to the union constraint of the type parameter;
|
||||
// (3) The extends type `A` is a type or a union of types that are supertypes of the union constraint of the type parameter;
|
||||
// (4) `TrueBranch<T>` and `FalseBranch<T>` must be valid, recursively.
|
||||
// In particular, the false-most branch of the conditional type must be `never`.
|
||||
function isNarrowableConditionalTypeWorker(type: ConditionalType): boolean {
|
||||
@@ -46111,7 +46111,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
!everyType(type.extendsType, extendsType =>
|
||||
some(
|
||||
(constraintType as UnionType).types,
|
||||
constraintType => isTypeIdenticalTo(constraintType, extendsType),
|
||||
constraintType => isTypeAssignableTo(constraintType, extendsType),
|
||||
))
|
||||
) {
|
||||
return false;
|
||||
|
||||
@@ -26,8 +26,6 @@ dependentReturnType1.ts(275,9): error TS2322: Type '1' is not assignable to type
|
||||
dependentReturnType1.ts(278,9): error TS2322: Type '2' is not assignable to type 'HelperCond<{ x: U; y: V; }, { x: string; y: true; }, 1, { x: number; y: false; }, 2>'.
|
||||
dependentReturnType1.ts(280,5): error TS2322: Type '0' is not assignable to type 'HelperCond<{ x: U; y: V; }, { x: string; y: true; }, 1, { x: number; y: false; }, 2>'.
|
||||
dependentReturnType1.ts(302,9): error TS2322: Type 'string' is not assignable to type 'string[]'.
|
||||
dependentReturnType1.ts(311,9): error TS2322: Type 'undefined' is not assignable to type 'T extends {} ? void : T extends undefined ? number : never'.
|
||||
dependentReturnType1.ts(313,5): error TS2322: Type 'number' is not assignable to type 'T extends {} ? void : T extends undefined ? number : never'.
|
||||
dependentReturnType1.ts(334,9): error TS2322: Type '1' is not assignable to type '4'.
|
||||
dependentReturnType1.ts(367,13): error TS2322: Type 'number' is not assignable to type 'T extends 1 ? number : T extends 2 ? string : never'.
|
||||
dependentReturnType1.ts(369,9): error TS2322: Type 'string' is not assignable to type 'T extends 1 ? number : T extends 2 ? string : never'.
|
||||
@@ -44,7 +42,7 @@ dependentReturnType1.ts(488,9): error TS2322: Type 'R' is not assignable to type
|
||||
dependentReturnType1.ts(514,5): error TS2322: Type '1' is not assignable to type 'never'.
|
||||
|
||||
|
||||
==== dependentReturnType1.ts (39 errors) ====
|
||||
==== dependentReturnType1.ts (37 errors) ====
|
||||
interface A {
|
||||
1: number;
|
||||
2: string;
|
||||
@@ -407,12 +405,8 @@ dependentReturnType1.ts(514,5): error TS2322: Type '1' is not assignable to type
|
||||
): T extends {} ? void : T extends undefined ? number : never {
|
||||
if (x) {
|
||||
return;
|
||||
~~~~~~
|
||||
!!! error TS2322: Type 'undefined' is not assignable to type 'T extends {} ? void : T extends undefined ? number : never'.
|
||||
}
|
||||
return 1;
|
||||
~~~~~~
|
||||
!!! error TS2322: Type 'number' is not assignable to type 'T extends {} ? void : T extends undefined ? number : never'.
|
||||
}
|
||||
|
||||
// Multiple type parameters at once
|
||||
|
||||
41
tests/baselines/reference/dependentReturnType10.errors.txt
Normal file
41
tests/baselines/reference/dependentReturnType10.errors.txt
Normal file
@@ -0,0 +1,41 @@
|
||||
dependentReturnType10.ts(29,9): error TS2322: Type 'number' is not assignable to type 'void'.
|
||||
|
||||
|
||||
==== dependentReturnType10.ts (1 errors) ====
|
||||
interface Animal {
|
||||
name: string;
|
||||
species: string;
|
||||
}
|
||||
|
||||
interface Dog extends Animal {
|
||||
breed: string;
|
||||
}
|
||||
|
||||
type GreetRet<T> =
|
||||
T extends string ? string :
|
||||
T extends { name: string } ? { greeting: string, breed: string } :
|
||||
never;
|
||||
|
||||
function greet<T extends string | Dog>(animal: T): GreetRet<T> {
|
||||
if (typeof animal === "string") {
|
||||
return `hello, ${animal}`
|
||||
}
|
||||
return { greeting: `woof, ${animal.name}`, breed: animal.breed }
|
||||
}
|
||||
|
||||
type BadRet<T> =
|
||||
T extends {} ? void :
|
||||
T extends string ? number :
|
||||
never;
|
||||
|
||||
function badFun<T extends { a: string } | string>(x: T): BadRet<T> {
|
||||
if (typeof x === "string") {
|
||||
return 1
|
||||
~~~~~~
|
||||
!!! error TS2322: Type 'number' is not assignable to type 'void'.
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
declare let arg2: { a: string } | string;
|
||||
const badRet = badFun(arg2);
|
||||
100
tests/baselines/reference/dependentReturnType10.symbols
Normal file
100
tests/baselines/reference/dependentReturnType10.symbols
Normal file
@@ -0,0 +1,100 @@
|
||||
//// [tests/cases/compiler/dependentReturnType10.ts] ////
|
||||
|
||||
=== dependentReturnType10.ts ===
|
||||
interface Animal {
|
||||
>Animal : Symbol(Animal, Decl(dependentReturnType10.ts, 0, 0))
|
||||
|
||||
name: string;
|
||||
>name : Symbol(Animal.name, Decl(dependentReturnType10.ts, 0, 18))
|
||||
|
||||
species: string;
|
||||
>species : Symbol(Animal.species, Decl(dependentReturnType10.ts, 1, 17))
|
||||
}
|
||||
|
||||
interface Dog extends Animal {
|
||||
>Dog : Symbol(Dog, Decl(dependentReturnType10.ts, 3, 1))
|
||||
>Animal : Symbol(Animal, Decl(dependentReturnType10.ts, 0, 0))
|
||||
|
||||
breed: string;
|
||||
>breed : Symbol(Dog.breed, Decl(dependentReturnType10.ts, 5, 30))
|
||||
}
|
||||
|
||||
type GreetRet<T> =
|
||||
>GreetRet : Symbol(GreetRet, Decl(dependentReturnType10.ts, 7, 1))
|
||||
>T : Symbol(T, Decl(dependentReturnType10.ts, 9, 14))
|
||||
|
||||
T extends string ? string :
|
||||
>T : Symbol(T, Decl(dependentReturnType10.ts, 9, 14))
|
||||
|
||||
T extends { name: string } ? { greeting: string, breed: string } :
|
||||
>T : Symbol(T, Decl(dependentReturnType10.ts, 9, 14))
|
||||
>name : Symbol(name, Decl(dependentReturnType10.ts, 11, 15))
|
||||
>greeting : Symbol(greeting, Decl(dependentReturnType10.ts, 11, 34))
|
||||
>breed : Symbol(breed, Decl(dependentReturnType10.ts, 11, 52))
|
||||
|
||||
never;
|
||||
|
||||
function greet<T extends string | Dog>(animal: T): GreetRet<T> {
|
||||
>greet : Symbol(greet, Decl(dependentReturnType10.ts, 12, 10))
|
||||
>T : Symbol(T, Decl(dependentReturnType10.ts, 14, 15))
|
||||
>Dog : Symbol(Dog, Decl(dependentReturnType10.ts, 3, 1))
|
||||
>animal : Symbol(animal, Decl(dependentReturnType10.ts, 14, 39))
|
||||
>T : Symbol(T, Decl(dependentReturnType10.ts, 14, 15))
|
||||
>GreetRet : Symbol(GreetRet, Decl(dependentReturnType10.ts, 7, 1))
|
||||
>T : Symbol(T, Decl(dependentReturnType10.ts, 14, 15))
|
||||
|
||||
if (typeof animal === "string") {
|
||||
>animal : Symbol(animal, Decl(dependentReturnType10.ts, 14, 39))
|
||||
|
||||
return `hello, ${animal}`
|
||||
>animal : Symbol(animal, Decl(dependentReturnType10.ts, 14, 39))
|
||||
}
|
||||
return { greeting: `woof, ${animal.name}`, breed: animal.breed }
|
||||
>greeting : Symbol(greeting, Decl(dependentReturnType10.ts, 18, 12))
|
||||
>animal.name : Symbol(Animal.name, Decl(dependentReturnType10.ts, 0, 18))
|
||||
>animal : Symbol(animal, Decl(dependentReturnType10.ts, 14, 39))
|
||||
>name : Symbol(Animal.name, Decl(dependentReturnType10.ts, 0, 18))
|
||||
>breed : Symbol(breed, Decl(dependentReturnType10.ts, 18, 46))
|
||||
>animal.breed : Symbol(Dog.breed, Decl(dependentReturnType10.ts, 5, 30))
|
||||
>animal : Symbol(animal, Decl(dependentReturnType10.ts, 14, 39))
|
||||
>breed : Symbol(Dog.breed, Decl(dependentReturnType10.ts, 5, 30))
|
||||
}
|
||||
|
||||
type BadRet<T> =
|
||||
>BadRet : Symbol(BadRet, Decl(dependentReturnType10.ts, 19, 1))
|
||||
>T : Symbol(T, Decl(dependentReturnType10.ts, 21, 12))
|
||||
|
||||
T extends {} ? void :
|
||||
>T : Symbol(T, Decl(dependentReturnType10.ts, 21, 12))
|
||||
|
||||
T extends string ? number :
|
||||
>T : Symbol(T, Decl(dependentReturnType10.ts, 21, 12))
|
||||
|
||||
never;
|
||||
|
||||
function badFun<T extends { a: string } | string>(x: T): BadRet<T> {
|
||||
>badFun : Symbol(badFun, Decl(dependentReturnType10.ts, 24, 10))
|
||||
>T : Symbol(T, Decl(dependentReturnType10.ts, 26, 16))
|
||||
>a : Symbol(a, Decl(dependentReturnType10.ts, 26, 27))
|
||||
>x : Symbol(x, Decl(dependentReturnType10.ts, 26, 50))
|
||||
>T : Symbol(T, Decl(dependentReturnType10.ts, 26, 16))
|
||||
>BadRet : Symbol(BadRet, Decl(dependentReturnType10.ts, 19, 1))
|
||||
>T : Symbol(T, Decl(dependentReturnType10.ts, 26, 16))
|
||||
|
||||
if (typeof x === "string") {
|
||||
>x : Symbol(x, Decl(dependentReturnType10.ts, 26, 50))
|
||||
|
||||
return 1
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
declare let arg2: { a: string } | string;
|
||||
>arg2 : Symbol(arg2, Decl(dependentReturnType10.ts, 33, 11))
|
||||
>a : Symbol(a, Decl(dependentReturnType10.ts, 33, 19))
|
||||
|
||||
const badRet = badFun(arg2);
|
||||
>badRet : Symbol(badRet, Decl(dependentReturnType10.ts, 34, 5))
|
||||
>badFun : Symbol(badFun, Decl(dependentReturnType10.ts, 24, 10))
|
||||
>arg2 : Symbol(arg2, Decl(dependentReturnType10.ts, 33, 11))
|
||||
|
||||
128
tests/baselines/reference/dependentReturnType10.types
Normal file
128
tests/baselines/reference/dependentReturnType10.types
Normal file
@@ -0,0 +1,128 @@
|
||||
//// [tests/cases/compiler/dependentReturnType10.ts] ////
|
||||
|
||||
=== dependentReturnType10.ts ===
|
||||
interface Animal {
|
||||
name: string;
|
||||
>name : string
|
||||
> : ^^^^^^
|
||||
|
||||
species: string;
|
||||
>species : string
|
||||
> : ^^^^^^
|
||||
}
|
||||
|
||||
interface Dog extends Animal {
|
||||
breed: string;
|
||||
>breed : string
|
||||
> : ^^^^^^
|
||||
}
|
||||
|
||||
type GreetRet<T> =
|
||||
>GreetRet : GreetRet<T>
|
||||
> : ^^^^^^^^^^^
|
||||
|
||||
T extends string ? string :
|
||||
T extends { name: string } ? { greeting: string, breed: string } :
|
||||
>name : string
|
||||
> : ^^^^^^
|
||||
>greeting : string
|
||||
> : ^^^^^^
|
||||
>breed : string
|
||||
> : ^^^^^^
|
||||
|
||||
never;
|
||||
|
||||
function greet<T extends string | Dog>(animal: T): GreetRet<T> {
|
||||
>greet : <T extends string | Dog>(animal: T) => GreetRet<T>
|
||||
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
|
||||
>animal : T
|
||||
> : ^
|
||||
|
||||
if (typeof animal === "string") {
|
||||
>typeof animal === "string" : boolean
|
||||
> : ^^^^^^^
|
||||
>typeof animal : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>animal : T
|
||||
> : ^
|
||||
>"string" : "string"
|
||||
> : ^^^^^^^^
|
||||
|
||||
return `hello, ${animal}`
|
||||
>`hello, ${animal}` : string
|
||||
> : ^^^^^^
|
||||
>animal : T & string
|
||||
> : ^^^^^^^^^^
|
||||
}
|
||||
return { greeting: `woof, ${animal.name}`, breed: animal.breed }
|
||||
>{ greeting: `woof, ${animal.name}`, breed: animal.breed } : { greeting: string; breed: string; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>greeting : string
|
||||
> : ^^^^^^
|
||||
>`woof, ${animal.name}` : string
|
||||
> : ^^^^^^
|
||||
>animal.name : string
|
||||
> : ^^^^^^
|
||||
>animal : Dog
|
||||
> : ^^^
|
||||
>name : string
|
||||
> : ^^^^^^
|
||||
>breed : string
|
||||
> : ^^^^^^
|
||||
>animal.breed : string
|
||||
> : ^^^^^^
|
||||
>animal : Dog
|
||||
> : ^^^
|
||||
>breed : string
|
||||
> : ^^^^^^
|
||||
}
|
||||
|
||||
type BadRet<T> =
|
||||
>BadRet : BadRet<T>
|
||||
> : ^^^^^^^^^
|
||||
|
||||
T extends {} ? void :
|
||||
T extends string ? number :
|
||||
never;
|
||||
|
||||
function badFun<T extends { a: string } | string>(x: T): BadRet<T> {
|
||||
>badFun : <T extends { a: string; } | string>(x: T) => BadRet<T>
|
||||
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
|
||||
>a : string
|
||||
> : ^^^^^^
|
||||
>x : T
|
||||
> : ^
|
||||
|
||||
if (typeof x === "string") {
|
||||
>typeof x === "string" : boolean
|
||||
> : ^^^^^^^
|
||||
>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>x : T
|
||||
> : ^
|
||||
>"string" : "string"
|
||||
> : ^^^^^^^^
|
||||
|
||||
return 1
|
||||
>1 : 1
|
||||
> : ^
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
declare let arg2: { a: string } | string;
|
||||
>arg2 : string | { a: string; }
|
||||
> : ^^^^^^^^^^^^^^ ^^^
|
||||
>a : string
|
||||
> : ^^^^^^
|
||||
|
||||
const badRet = badFun(arg2);
|
||||
>badRet : void
|
||||
> : ^^^^
|
||||
>badFun(arg2) : void
|
||||
> : ^^^^
|
||||
>badFun : <T extends { a: string; } | string>(x: T) => BadRet<T>
|
||||
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
|
||||
>arg2 : string | { a: string; }
|
||||
> : ^^^^^^^^^^^^^^ ^^^
|
||||
|
||||
37
tests/cases/compiler/dependentReturnType10.ts
Normal file
37
tests/cases/compiler/dependentReturnType10.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
// @noEmit: true
|
||||
|
||||
interface Animal {
|
||||
name: string;
|
||||
species: string;
|
||||
}
|
||||
|
||||
interface Dog extends Animal {
|
||||
breed: string;
|
||||
}
|
||||
|
||||
type GreetRet<T> =
|
||||
T extends string ? string :
|
||||
T extends { name: string } ? { greeting: string, breed: string } :
|
||||
never;
|
||||
|
||||
function greet<T extends string | Dog>(animal: T): GreetRet<T> {
|
||||
if (typeof animal === "string") {
|
||||
return `hello, ${animal}`
|
||||
}
|
||||
return { greeting: `woof, ${animal.name}`, breed: animal.breed }
|
||||
}
|
||||
|
||||
type BadRet<T> =
|
||||
T extends {} ? void :
|
||||
T extends string ? number :
|
||||
never;
|
||||
|
||||
function badFun<T extends { a: string } | string>(x: T): BadRet<T> {
|
||||
if (typeof x === "string") {
|
||||
return 1
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
declare let arg2: { a: string } | string;
|
||||
const badRet = badFun(arg2);
|
||||
Reference in New Issue
Block a user