Merge pull request #21627 from Microsoft/fixExtendsNever

Fix 'T extends never' in conditional types
This commit is contained in:
Anders Hejlsberg
2018-02-05 11:21:06 -08:00
committed by GitHub
7 changed files with 109 additions and 49 deletions
+10 -8
View File
@@ -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 &&
+1 -1
View File
@@ -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
+20 -10
View File
@@ -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