Skip to content
Merged
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
18 changes: 10 additions & 8 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 &&
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3564,7 +3564,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 */
Expand Down
16 changes: 11 additions & 5 deletions tests/baselines/reference/conditionalTypes1.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

30 changes: 20 additions & 10 deletions tests/baselines/reference/conditionalTypes1.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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>;
Expand All @@ -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>;
37 changes: 27 additions & 10 deletions tests/baselines/reference/conditionalTypes1.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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))

39 changes: 29 additions & 10 deletions tests/baselines/reference/conditionalTypes1.types
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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>

16 changes: 11 additions & 5 deletions tests/cases/conformance/types/conditional/conditionalTypes1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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