mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge pull request #21627 from Microsoft/fixExtendsNever
Fix 'T extends never' in conditional types
This commit is contained in:
+10
-8
@@ -315,6 +315,7 @@ namespace ts {
|
||||
|
||||
const anyType = createIntrinsicType(TypeFlags.Any, "any");
|
||||
const autoType = createIntrinsicType(TypeFlags.Any, "any");
|
||||
const wildcardType = createIntrinsicType(TypeFlags.Any, "any");
|
||||
const unknownType = createIntrinsicType(TypeFlags.Any, "unknown");
|
||||
const undefinedType = createIntrinsicType(TypeFlags.Undefined, "undefined");
|
||||
const undefinedWideningType = strictNullChecks ? undefinedType : createIntrinsicType(TypeFlags.Undefined | TypeFlags.ContainsWideningType, "undefined");
|
||||
@@ -8150,9 +8151,10 @@ namespace ts {
|
||||
// Instantiate extends type without instantiating any 'infer T' type parameters
|
||||
const extendsType = instantiateType(baseExtendsType, mapper);
|
||||
// Return falseType for a definitely false extends check. We check an instantations of the two
|
||||
// types with type parameters mapped to any, the most permissive instantiations possible. If those
|
||||
// are not related, then no instatiations will be and we can just return the false branch type.
|
||||
if (!isTypeAssignableTo(getAnyInstantiation(checkType), getAnyInstantiation(extendsType))) {
|
||||
// types with type parameters mapped to the wildcard type, the most permissive instantiations
|
||||
// possible (the wildcard type is assignable to and from all types). If those are not related,
|
||||
// then no instatiations will be and we can just return the false branch type.
|
||||
if (!isTypeAssignableTo(getWildcardInstantiation(checkType), getWildcardInstantiation(extendsType))) {
|
||||
return instantiateType(baseFalseType, mapper);
|
||||
}
|
||||
// The check could be true for some instantiation
|
||||
@@ -8615,8 +8617,8 @@ namespace ts {
|
||||
return t => t === source ? target : baseMapper(t);
|
||||
}
|
||||
|
||||
function anyMapper(type: Type) {
|
||||
return type.flags & TypeFlags.TypeParameter ? anyType : type;
|
||||
function wildcardMapper(type: Type) {
|
||||
return type.flags & TypeFlags.TypeParameter ? wildcardType : type;
|
||||
}
|
||||
|
||||
function cloneTypeParameter(typeParameter: TypeParameter): TypeParameter {
|
||||
@@ -8873,9 +8875,9 @@ namespace ts {
|
||||
return type;
|
||||
}
|
||||
|
||||
function getAnyInstantiation(type: Type) {
|
||||
function getWildcardInstantiation(type: Type) {
|
||||
return type.flags & (TypeFlags.Primitive | TypeFlags.Any | TypeFlags.Never) ? type :
|
||||
type.resolvedAnyInstantiation || (type.resolvedAnyInstantiation = instantiateType(type, anyMapper));
|
||||
type.wildcardInstantiation || (type.wildcardInstantiation = instantiateType(type, wildcardMapper));
|
||||
}
|
||||
|
||||
function instantiateIndexInfo(info: IndexInfo, mapper: TypeMapper): IndexInfo {
|
||||
@@ -9282,7 +9284,7 @@ namespace ts {
|
||||
function isSimpleTypeRelatedTo(source: Type, target: Type, relation: Map<RelationComparisonResult>, errorReporter?: ErrorReporter) {
|
||||
const s = source.flags;
|
||||
const t = target.flags;
|
||||
if (t & TypeFlags.Any || s & TypeFlags.Never) return true;
|
||||
if (t & TypeFlags.Any || s & TypeFlags.Never || source === wildcardType) return true;
|
||||
if (t & TypeFlags.Never) return false;
|
||||
if (s & TypeFlags.StringLike && t & TypeFlags.String) return true;
|
||||
if (s & TypeFlags.StringLiteral && s & TypeFlags.EnumLiteral &&
|
||||
|
||||
@@ -3565,7 +3565,7 @@ namespace ts {
|
||||
aliasSymbol?: Symbol; // Alias associated with type
|
||||
aliasTypeArguments?: Type[]; // Alias type arguments (if any)
|
||||
/* @internal */
|
||||
resolvedAnyInstantiation?: Type; // Instantiation with type parameters mapped to any
|
||||
wildcardInstantiation?: Type; // Instantiation with type parameters mapped to wildcard type
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
|
||||
@@ -304,12 +304,12 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(157,5): error TS2
|
||||
type And<A extends boolean, B extends boolean> = If<A, B, false>;
|
||||
type Or<A extends boolean, B extends boolean> = If<A, true, B>;
|
||||
|
||||
type isString<T> = Extends<T, string>;
|
||||
type IsString<T> = Extends<T, string>;
|
||||
|
||||
type Q1 = isString<number>; // false
|
||||
type Q2 = isString<"abc">; // true
|
||||
type Q3 = isString<any>; // boolean
|
||||
type Q4 = isString<never>; // boolean
|
||||
type Q1 = IsString<number>; // false
|
||||
type Q2 = IsString<"abc">; // true
|
||||
type Q3 = IsString<any>; // boolean
|
||||
type Q4 = IsString<never>; // boolean
|
||||
|
||||
type N1 = Not<false>; // true
|
||||
type N2 = Not<true>; // false
|
||||
@@ -338,4 +338,10 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(157,5): error TS2
|
||||
type T40 = never extends never ? true : false; // true
|
||||
type T41 = number extends never ? true : false; // false
|
||||
type T42 = never extends number ? true : false; // boolean
|
||||
|
||||
type IsNever<T> = T extends never ? true : false;
|
||||
|
||||
type T50 = IsNever<never>; // true
|
||||
type T51 = IsNever<number>; // false
|
||||
type T52 = IsNever<any>; // false
|
||||
|
||||
@@ -164,12 +164,12 @@ type Not<C extends boolean> = If<C, false, true>;
|
||||
type And<A extends boolean, B extends boolean> = If<A, B, false>;
|
||||
type Or<A extends boolean, B extends boolean> = If<A, true, B>;
|
||||
|
||||
type isString<T> = Extends<T, string>;
|
||||
type IsString<T> = Extends<T, string>;
|
||||
|
||||
type Q1 = isString<number>; // false
|
||||
type Q2 = isString<"abc">; // true
|
||||
type Q3 = isString<any>; // boolean
|
||||
type Q4 = isString<never>; // boolean
|
||||
type Q1 = IsString<number>; // false
|
||||
type Q2 = IsString<"abc">; // true
|
||||
type Q3 = IsString<any>; // boolean
|
||||
type Q4 = IsString<never>; // boolean
|
||||
|
||||
type N1 = Not<false>; // true
|
||||
type N2 = Not<true>; // false
|
||||
@@ -198,6 +198,12 @@ type O9 = Or<boolean, boolean>; // boolean
|
||||
type T40 = never extends never ? true : false; // true
|
||||
type T41 = number extends never ? true : false; // false
|
||||
type T42 = never extends number ? true : false; // boolean
|
||||
|
||||
type IsNever<T> = T extends never ? true : false;
|
||||
|
||||
type T50 = IsNever<never>; // true
|
||||
type T51 = IsNever<number>; // false
|
||||
type T52 = IsNever<any>; // false
|
||||
|
||||
|
||||
//// [conditionalTypes1.js]
|
||||
@@ -376,11 +382,11 @@ declare type If<C extends boolean, T, F> = C extends true ? T : F;
|
||||
declare type Not<C extends boolean> = If<C, false, true>;
|
||||
declare type And<A extends boolean, B extends boolean> = If<A, B, false>;
|
||||
declare type Or<A extends boolean, B extends boolean> = If<A, true, B>;
|
||||
declare type isString<T> = Extends<T, string>;
|
||||
declare type Q1 = isString<number>;
|
||||
declare type Q2 = isString<"abc">;
|
||||
declare type Q3 = isString<any>;
|
||||
declare type Q4 = isString<never>;
|
||||
declare type IsString<T> = Extends<T, string>;
|
||||
declare type Q1 = IsString<number>;
|
||||
declare type Q2 = IsString<"abc">;
|
||||
declare type Q3 = IsString<any>;
|
||||
declare type Q4 = IsString<never>;
|
||||
declare type N1 = Not<false>;
|
||||
declare type N2 = Not<true>;
|
||||
declare type N3 = Not<boolean>;
|
||||
@@ -405,3 +411,7 @@ declare type O9 = Or<boolean, boolean>;
|
||||
declare type T40 = never extends never ? true : false;
|
||||
declare type T41 = number extends never ? true : false;
|
||||
declare type T42 = never extends number ? true : false;
|
||||
declare type IsNever<T> = T extends never ? true : false;
|
||||
declare type T50 = IsNever<never>;
|
||||
declare type T51 = IsNever<number>;
|
||||
declare type T52 = IsNever<any>;
|
||||
|
||||
@@ -645,27 +645,27 @@ type Or<A extends boolean, B extends boolean> = If<A, true, B>;
|
||||
>A : Symbol(A, Decl(conditionalTypes1.ts, 163, 8))
|
||||
>B : Symbol(B, Decl(conditionalTypes1.ts, 163, 26))
|
||||
|
||||
type isString<T> = Extends<T, string>;
|
||||
>isString : Symbol(isString, Decl(conditionalTypes1.ts, 163, 63))
|
||||
type IsString<T> = Extends<T, string>;
|
||||
>IsString : Symbol(IsString, Decl(conditionalTypes1.ts, 163, 63))
|
||||
>T : Symbol(T, Decl(conditionalTypes1.ts, 165, 14))
|
||||
>Extends : Symbol(Extends, Decl(conditionalTypes1.ts, 157, 1))
|
||||
>T : Symbol(T, Decl(conditionalTypes1.ts, 165, 14))
|
||||
|
||||
type Q1 = isString<number>; // false
|
||||
type Q1 = IsString<number>; // false
|
||||
>Q1 : Symbol(Q1, Decl(conditionalTypes1.ts, 165, 38))
|
||||
>isString : Symbol(isString, Decl(conditionalTypes1.ts, 163, 63))
|
||||
>IsString : Symbol(IsString, Decl(conditionalTypes1.ts, 163, 63))
|
||||
|
||||
type Q2 = isString<"abc">; // true
|
||||
type Q2 = IsString<"abc">; // true
|
||||
>Q2 : Symbol(Q2, Decl(conditionalTypes1.ts, 167, 27))
|
||||
>isString : Symbol(isString, Decl(conditionalTypes1.ts, 163, 63))
|
||||
>IsString : Symbol(IsString, Decl(conditionalTypes1.ts, 163, 63))
|
||||
|
||||
type Q3 = isString<any>; // boolean
|
||||
type Q3 = IsString<any>; // boolean
|
||||
>Q3 : Symbol(Q3, Decl(conditionalTypes1.ts, 168, 26))
|
||||
>isString : Symbol(isString, Decl(conditionalTypes1.ts, 163, 63))
|
||||
>IsString : Symbol(IsString, Decl(conditionalTypes1.ts, 163, 63))
|
||||
|
||||
type Q4 = isString<never>; // boolean
|
||||
type Q4 = IsString<never>; // boolean
|
||||
>Q4 : Symbol(Q4, Decl(conditionalTypes1.ts, 169, 24))
|
||||
>isString : Symbol(isString, Decl(conditionalTypes1.ts, 163, 63))
|
||||
>IsString : Symbol(IsString, Decl(conditionalTypes1.ts, 163, 63))
|
||||
|
||||
type N1 = Not<false>; // true
|
||||
>N1 : Symbol(N1, Decl(conditionalTypes1.ts, 170, 26))
|
||||
@@ -760,3 +760,20 @@ type T41 = number extends never ? true : false; // false
|
||||
type T42 = never extends number ? true : false; // boolean
|
||||
>T42 : Symbol(T42, Decl(conditionalTypes1.ts, 197, 47))
|
||||
|
||||
type IsNever<T> = T extends never ? true : false;
|
||||
>IsNever : Symbol(IsNever, Decl(conditionalTypes1.ts, 198, 47))
|
||||
>T : Symbol(T, Decl(conditionalTypes1.ts, 200, 13))
|
||||
>T : Symbol(T, Decl(conditionalTypes1.ts, 200, 13))
|
||||
|
||||
type T50 = IsNever<never>; // true
|
||||
>T50 : Symbol(T50, Decl(conditionalTypes1.ts, 200, 49))
|
||||
>IsNever : Symbol(IsNever, Decl(conditionalTypes1.ts, 198, 47))
|
||||
|
||||
type T51 = IsNever<number>; // false
|
||||
>T51 : Symbol(T51, Decl(conditionalTypes1.ts, 202, 26))
|
||||
>IsNever : Symbol(IsNever, Decl(conditionalTypes1.ts, 198, 47))
|
||||
|
||||
type T52 = IsNever<any>; // false
|
||||
>T52 : Symbol(T52, Decl(conditionalTypes1.ts, 203, 27))
|
||||
>IsNever : Symbol(IsNever, Decl(conditionalTypes1.ts, 198, 47))
|
||||
|
||||
|
||||
@@ -717,27 +717,27 @@ type Or<A extends boolean, B extends boolean> = If<A, true, B>;
|
||||
>true : true
|
||||
>B : B
|
||||
|
||||
type isString<T> = Extends<T, string>;
|
||||
>isString : Extends<T, string>
|
||||
type IsString<T> = Extends<T, string>;
|
||||
>IsString : Extends<T, string>
|
||||
>T : T
|
||||
>Extends : Extends<T, U>
|
||||
>T : T
|
||||
|
||||
type Q1 = isString<number>; // false
|
||||
type Q1 = IsString<number>; // false
|
||||
>Q1 : false
|
||||
>isString : Extends<T, string>
|
||||
>IsString : Extends<T, string>
|
||||
|
||||
type Q2 = isString<"abc">; // true
|
||||
type Q2 = IsString<"abc">; // true
|
||||
>Q2 : true
|
||||
>isString : Extends<T, string>
|
||||
>IsString : Extends<T, string>
|
||||
|
||||
type Q3 = isString<any>; // boolean
|
||||
type Q3 = IsString<any>; // boolean
|
||||
>Q3 : boolean
|
||||
>isString : Extends<T, string>
|
||||
>IsString : Extends<T, string>
|
||||
|
||||
type Q4 = isString<never>; // boolean
|
||||
type Q4 = IsString<never>; // boolean
|
||||
>Q4 : boolean
|
||||
>isString : Extends<T, string>
|
||||
>IsString : Extends<T, string>
|
||||
|
||||
type N1 = Not<false>; // true
|
||||
>N1 : true
|
||||
@@ -864,3 +864,22 @@ type T42 = never extends number ? true : false; // boolean
|
||||
>true : true
|
||||
>false : false
|
||||
|
||||
type IsNever<T> = T extends never ? true : false;
|
||||
>IsNever : IsNever<T>
|
||||
>T : T
|
||||
>T : T
|
||||
>true : true
|
||||
>false : false
|
||||
|
||||
type T50 = IsNever<never>; // true
|
||||
>T50 : true
|
||||
>IsNever : IsNever<T>
|
||||
|
||||
type T51 = IsNever<number>; // false
|
||||
>T51 : false
|
||||
>IsNever : IsNever<T>
|
||||
|
||||
type T52 = IsNever<any>; // false
|
||||
>T52 : false
|
||||
>IsNever : IsNever<T>
|
||||
|
||||
|
||||
@@ -166,12 +166,12 @@ type Not<C extends boolean> = If<C, false, true>;
|
||||
type And<A extends boolean, B extends boolean> = If<A, B, false>;
|
||||
type Or<A extends boolean, B extends boolean> = If<A, true, B>;
|
||||
|
||||
type isString<T> = Extends<T, string>;
|
||||
type IsString<T> = Extends<T, string>;
|
||||
|
||||
type Q1 = isString<number>; // false
|
||||
type Q2 = isString<"abc">; // true
|
||||
type Q3 = isString<any>; // boolean
|
||||
type Q4 = isString<never>; // boolean
|
||||
type Q1 = IsString<number>; // false
|
||||
type Q2 = IsString<"abc">; // true
|
||||
type Q3 = IsString<any>; // boolean
|
||||
type Q4 = IsString<never>; // boolean
|
||||
|
||||
type N1 = Not<false>; // true
|
||||
type N2 = Not<true>; // false
|
||||
@@ -200,3 +200,9 @@ type O9 = Or<boolean, boolean>; // boolean
|
||||
type T40 = never extends never ? true : false; // true
|
||||
type T41 = number extends never ? true : false; // false
|
||||
type T42 = never extends number ? true : false; // boolean
|
||||
|
||||
type IsNever<T> = T extends never ? true : false;
|
||||
|
||||
type T50 = IsNever<never>; // true
|
||||
type T51 = IsNever<number>; // false
|
||||
type T52 = IsNever<any>; // false
|
||||
|
||||
Reference in New Issue
Block a user