Merge pull request #22197 from Microsoft/fixConditionalTypes

Conditional type fixes
This commit is contained in:
Anders Hejlsberg
2018-03-01 10:27:15 -08:00
committed by GitHub
15 changed files with 239 additions and 169 deletions

View File

@@ -318,7 +318,6 @@ namespace ts {
const intersectionTypes = createMap<IntersectionType>();
const literalTypes = createMap<LiteralType>();
const indexedAccessTypes = createMap<IndexedAccessType>();
const conditionalTypes = createMap<ConditionalType>();
const evolvingArrayTypes: EvolvingArrayType[] = [];
const undefinedProperties = createMap<Symbol>() as UnderscoreEscapedMap<Symbol>;
@@ -600,6 +599,7 @@ namespace ts {
ObjectType = 1 << 9,
EmptyObject = 1 << 10,
Union = 1 << 11,
Wildcard = 1 << 12,
}
const enum MembersOrExportsResolutionKind {
@@ -2975,8 +2975,8 @@ namespace ts {
if (type.flags & TypeFlags.Conditional) {
const checkTypeNode = typeToTypeNodeHelper((<ConditionalType>type).checkType, context);
const extendsTypeNode = typeToTypeNodeHelper((<ConditionalType>type).extendsType, context);
const trueTypeNode = typeToTypeNodeHelper((<ConditionalType>type).trueType, context);
const falseTypeNode = typeToTypeNodeHelper((<ConditionalType>type).falseType, context);
const trueTypeNode = typeToTypeNodeHelper(getTrueTypeFromConditionalType(<ConditionalType>type), context);
const falseTypeNode = typeToTypeNodeHelper(getFalseTypeFromConditionalType(<ConditionalType>type), context);
return createConditionalTypeNode(checkTypeNode, extendsTypeNode, trueTypeNode, falseTypeNode);
}
if (type.flags & TypeFlags.Substitution) {
@@ -5899,8 +5899,7 @@ namespace ts {
// Create a mapper from T to the current iteration type constituent. Then, if the
// mapped type is itself an instantiated type, combine the iteration mapper with the
// instantiation mapper.
const iterationMapper = createTypeMapper([typeParameter], [t]);
const templateMapper = type.mapper ? combineTypeMappers(type.mapper, iterationMapper) : iterationMapper;
const templateMapper = combineTypeMappers(type.mapper, createTypeMapper([typeParameter], [t]));
const propType = instantiateType(templateType, templateMapper);
// If the current iteration type constituent is a string literal type, create a property.
// Otherwise, for type string create a string index signature.
@@ -6122,22 +6121,20 @@ namespace ts {
}
function getDefaultConstraintOfConditionalType(type: ConditionalType) {
return getUnionType([type.trueType, type.falseType]);
return getUnionType([getTrueTypeFromConditionalType(type), getFalseTypeFromConditionalType(type)]);
}
function getConstraintOfDistributiveConditionalType(type: ConditionalType) {
function getConstraintOfDistributiveConditionalType(type: ConditionalType): Type {
// Check if we have a conditional type of the form 'T extends U ? X : Y', where T is a constrained
// type parameter. If so, create an instantiation of the conditional type where T is replaced
// with its constraint. We do this because if the constraint is a union type it will be distributed
// over the conditional type and possibly reduced. For example, 'T extends undefined ? never : T'
// removes 'undefined' from T.
if (isDistributiveConditionalType(type)) {
if (type.root.isDistributive) {
const constraint = getConstraintOfType(type.checkType);
if (constraint) {
const target = type.target || type;
const mapper = createTypeMapper([<TypeParameter>target.checkType], [constraint]);
const combinedMapper = type.mapper ? combineTypeMappers(mapper, type.mapper) : mapper;
return instantiateType(target, combinedMapper);
const mapper = createTypeMapper([<TypeParameter>type.root.checkType], [constraint]);
return getConditionalTypeInstantiation(type, combineTypeMappers(mapper, type.mapper));
}
}
return undefined;
@@ -6236,7 +6233,8 @@ namespace ts {
return baseIndexedAccess && baseIndexedAccess !== unknownType ? getBaseConstraint(baseIndexedAccess) : undefined;
}
if (t.flags & TypeFlags.Conditional) {
return getBaseConstraint(getConstraintOfConditionalType(<ConditionalType>t));
const constraint = getConstraintOfConditionalType(<ConditionalType>t);
return constraint && getBaseConstraint(constraint);
}
if (t.flags & TypeFlags.Substitution) {
return getBaseConstraint((<SubstitutionType>t).substitute);
@@ -7639,6 +7637,7 @@ namespace ts {
}
else if (flags & TypeFlags.Any) {
includes |= TypeIncludes.Any;
if (type === wildcardType) includes |= TypeIncludes.Wildcard;
}
else if (!strictNullChecks && flags & TypeFlags.Nullable) {
if (flags & TypeFlags.Undefined) includes |= TypeIncludes.Undefined;
@@ -7758,7 +7757,7 @@ namespace ts {
const typeSet: Type[] = [];
const includes = addTypesToUnion(typeSet, 0, types);
if (includes & TypeIncludes.Any) {
return anyType;
return includes & TypeIncludes.Wildcard ? wildcardType : anyType;
}
switch (unionReduction) {
case UnionReduction.Literal:
@@ -8140,7 +8139,7 @@ namespace ts {
function substituteIndexedMappedType(objectType: MappedType, type: IndexedAccessType) {
const mapper = createTypeMapper([getTypeParameterFromMappedType(objectType)], [type.indexType]);
const templateMapper = objectType.mapper ? combineTypeMappers(objectType.mapper, mapper) : mapper;
const templateMapper = combineTypeMappers(objectType.mapper, mapper);
return instantiateType(getTemplateTypeFromMappedType(objectType), templateMapper);
}
@@ -8207,76 +8206,59 @@ namespace ts {
return type.flags & TypeFlags.Substitution ? (<SubstitutionType>type).typeParameter : type;
}
function createConditionalType(checkType: Type, extendsType: Type, trueType: Type, falseType: Type, inferTypeParameters: TypeParameter[], target: ConditionalType, mapper: TypeMapper, aliasSymbol: Symbol, aliasTypeArguments: Type[]) {
const type = <ConditionalType>createType(TypeFlags.Conditional);
type.checkType = checkType;
type.extendsType = extendsType;
type.trueType = trueType;
type.falseType = falseType;
type.inferTypeParameters = inferTypeParameters;
type.target = target;
type.mapper = mapper;
type.aliasSymbol = aliasSymbol;
type.aliasTypeArguments = aliasTypeArguments;
return type;
}
function getConditionalType(checkType: Type, baseExtendsType: Type, baseTrueType: Type, baseFalseType: Type, inferTypeParameters: TypeParameter[], target: ConditionalType, mapper: TypeMapper, aliasSymbol?: Symbol, baseAliasTypeArguments?: Type[]): Type {
// Instantiate extends type without instantiating any 'infer T' type parameters
const extendsType = instantiateType(baseExtendsType, mapper);
function getConditionalType(root: ConditionalRoot, mapper: TypeMapper): Type {
const checkType = instantiateType(root.checkType, mapper);
const extendsType = instantiateType(root.extendsType, mapper);
// Return falseType for a definitely false extends check. We check an instantations of the two
// 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 (!typeMaybeAssignableTo(getWildcardInstantiation(checkType), getWildcardInstantiation(extendsType))) {
return instantiateType(baseFalseType, mapper);
return instantiateType(root.falseType, mapper);
}
// The check could be true for some instantiation
let combinedMapper: TypeMapper;
if (inferTypeParameters) {
const inferences = map(inferTypeParameters, createInferenceInfo);
if (root.inferTypeParameters) {
const inferences = map(root.inferTypeParameters, createInferenceInfo);
// We don't want inferences from constraints as they may cause us to eagerly resolve the
// conditional type instead of deferring resolution. Also, we always want strict function
// types rules (i.e. proper contravariance) for inferences.
inferTypes(inferences, checkType, extendsType, InferencePriority.NoConstraints | InferencePriority.AlwaysStrict);
// We infer 'never' when there are no candidates for a type parameter
const inferredTypes = map(inferences, inference => getTypeFromInference(inference) || neverType);
const inferenceMapper = createTypeMapper(inferTypeParameters, inferredTypes);
combinedMapper = mapper ? combineTypeMappers(mapper, inferenceMapper) : inferenceMapper;
// We infer {} when there are no candidates for a type parameter
const inferredTypes = map(inferences, inference => getTypeFromInference(inference) || emptyObjectType);
combinedMapper = combineTypeMappers(mapper, createTypeMapper(root.inferTypeParameters, inferredTypes));
}
// Return union of trueType and falseType for any and never since they match anything
if (checkType.flags & TypeFlags.Any || (checkType.flags & TypeFlags.Never && !(extendsType.flags & TypeFlags.Never))) {
return getUnionType([instantiateType(baseTrueType, combinedMapper || mapper), instantiateType(baseFalseType, mapper)]);
// Return union of trueType and falseType for 'any' since it matches anything
if (checkType.flags & TypeFlags.Any) {
return getUnionType([instantiateType(root.trueType, combinedMapper || mapper), instantiateType(root.falseType, mapper)]);
}
// Instantiate the extends type including inferences for 'infer T' type parameters
const inferredExtendsType = combinedMapper ? instantiateType(baseExtendsType, combinedMapper) : extendsType;
const inferredExtendsType = combinedMapper ? instantiateType(root.extendsType, combinedMapper) : extendsType;
// Return trueType for a definitely true extends check. The definitely assignable relation excludes
// type variable constraints from consideration. Without the definitely assignable relation, the type
// type Foo<T extends { x: any }> = T extends { x: string } ? string : number
// would immediately resolve to 'string' instead of being deferred.
if (checkTypeRelatedTo(checkType, inferredExtendsType, definitelyAssignableRelation, /*errorNode*/ undefined)) {
return instantiateType(baseTrueType, combinedMapper || mapper);
return instantiateType(root.trueType, combinedMapper || mapper);
}
// Return a deferred type for a check that is neither definitely true nor definitely false
const erasedCheckType = getActualTypeParameter(checkType);
const trueType = instantiateType(baseTrueType, mapper);
const falseType = instantiateType(baseFalseType, mapper);
// We compute the cache key from the ids of the four constituent types, plus an indicator of whether the
// type is distributive (i.e. whether the original declaration has a type parameter as the check type).
const isDistributive = (target ? target.checkType : erasedCheckType).flags & TypeFlags.TypeParameter ? 1 : 0;
const id = erasedCheckType.id + "," + extendsType.id + "," + trueType.id + "," + falseType.id + "," + isDistributive;
const cached = conditionalTypes.get(id);
if (cached) {
return cached;
}
const result = createConditionalType(erasedCheckType, extendsType, trueType, falseType,
inferTypeParameters, target, mapper, aliasSymbol, instantiateTypes(baseAliasTypeArguments, mapper));
conditionalTypes.set(id, result);
const result = <ConditionalType>createType(TypeFlags.Conditional);
result.root = root;
result.checkType = erasedCheckType;
result.extendsType = extendsType;
result.mapper = mapper;
result.aliasSymbol = root.aliasSymbol;
result.aliasTypeArguments = instantiateTypes(root.aliasTypeArguments, mapper);
return result;
}
function isDistributiveConditionalType(type: ConditionalType) {
return !!((type.target || type).checkType.flags & TypeFlags.TypeParameter);
function getTrueTypeFromConditionalType(type: ConditionalType) {
return type.resolvedTrueType || (type.resolvedTrueType = instantiateType(type.root.trueType, type.mapper));
}
function getFalseTypeFromConditionalType(type: ConditionalType) {
return type.resolvedFalseType || (type.resolvedFalseType = instantiateType(type.root.falseType, type.mapper));
}
function getInferTypeParameters(node: ConditionalTypeNode): TypeParameter[] {
@@ -8294,11 +8276,28 @@ namespace ts {
function getTypeFromConditionalTypeNode(node: ConditionalTypeNode): Type {
const links = getNodeLinks(node);
if (!links.resolvedType) {
links.resolvedType = getConditionalType(
getTypeFromTypeNode(node.checkType), getTypeFromTypeNode(node.extendsType),
getTypeFromTypeNode(node.trueType), getTypeFromTypeNode(node.falseType),
getInferTypeParameters(node), /*target*/ undefined, /*mapper*/ undefined,
getAliasSymbolForTypeNode(node), getAliasTypeArgumentsForTypeNode(node));
const checkType = getTypeFromTypeNode(node.checkType);
const aliasTypeArguments = getAliasTypeArgumentsForTypeNode(node);
const allOuterTypeParameters = getOuterTypeParameters(node, /*includeThisTypes*/ true);
const outerTypeParameters = aliasTypeArguments ? allOuterTypeParameters : filter(allOuterTypeParameters, tp => isTypeParameterPossiblyReferenced(tp, node));
const root: ConditionalRoot = {
node,
checkType,
extendsType: getTypeFromTypeNode(node.extendsType),
trueType: getTypeFromTypeNode(node.trueType),
falseType: getTypeFromTypeNode(node.falseType),
isDistributive: !!(checkType.flags & TypeFlags.TypeParameter),
inferTypeParameters: getInferTypeParameters(node),
outerTypeParameters,
instantiations: undefined,
aliasSymbol: getAliasSymbolForTypeNode(node),
aliasTypeArguments
};
links.resolvedType = getConditionalType(root, /*mapper*/ undefined);
if (outerTypeParameters) {
root.instantiations = createMap<Type>();
root.instantiations.set(getTypeListId(outerTypeParameters), links.resolvedType);
}
}
return links.resolvedType;
}
@@ -8689,6 +8688,8 @@ namespace ts {
}
function combineTypeMappers(mapper1: TypeMapper, mapper2: TypeMapper): TypeMapper {
if (!mapper1) return mapper2;
if (!mapper2) return mapper1;
return t => instantiateType(mapper1(t), mapper2);
}
@@ -8886,24 +8887,36 @@ namespace ts {
}
function getConditionalTypeInstantiation(type: ConditionalType, mapper: TypeMapper): Type {
const target = type.target || type;
const combinedMapper = type.mapper ? combineTypeMappers(type.mapper, mapper) : mapper;
const root = type.root;
if (root.outerTypeParameters) {
// We are instantiating a conditional type that has one or more type parameters in scope. Apply the
// mapper to the type parameters to produce the effective list of type arguments, and compute the
// instantiation cache key from the type IDs of the type arguments.
const typeArguments = map(root.outerTypeParameters, mapper);
const id = getTypeListId(typeArguments);
let result = root.instantiations.get(id);
if (!result) {
const newMapper = createTypeMapper(root.outerTypeParameters, typeArguments);
result = instantiateConditionalType(root, newMapper);
root.instantiations.set(id, result);
}
return result;
}
return type;
}
function instantiateConditionalType(root: ConditionalRoot, mapper: TypeMapper): Type {
// Check if we have a conditional type where the check type is a naked type parameter. If so,
// the conditional type is distributive over union types and when T is instantiated to a union
// type A | B, we produce (A extends U ? X : Y) | (B extends U ? X : Y).
if (isDistributiveConditionalType(target)) {
const checkType = <TypeParameter>target.checkType;
const instantiatedType = combinedMapper(checkType);
if (checkType !== instantiatedType && instantiatedType.flags & TypeFlags.Union) {
return mapType(instantiatedType, t => instantiateConditionalType(target, createReplacementMapper(checkType, t, combinedMapper)));
if (root.isDistributive) {
const checkType = <TypeParameter>root.checkType;
const instantiatedType = mapper(checkType);
if (checkType !== instantiatedType && instantiatedType.flags & (TypeFlags.Union | TypeFlags.Never)) {
return mapType(instantiatedType, t => getConditionalType(root, createReplacementMapper(checkType, t, mapper)));
}
}
return instantiateConditionalType(target, combinedMapper);
}
function instantiateConditionalType(type: ConditionalType, mapper: TypeMapper): Type {
return getConditionalType(instantiateType(type.checkType, mapper), type.extendsType, type.trueType, type.falseType,
type.inferTypeParameters, type, mapper, type.aliasSymbol, type.aliasTypeArguments);
return getConditionalType(root, mapper);
}
function instantiateType(type: Type, mapper: TypeMapper): Type {
@@ -8945,7 +8958,7 @@ namespace ts {
return getIndexedAccessType(instantiateType((<IndexedAccessType>type).objectType, mapper), instantiateType((<IndexedAccessType>type).indexType, mapper));
}
if (type.flags & TypeFlags.Conditional) {
return getConditionalTypeInstantiation(<ConditionalType>type, mapper);
return getConditionalTypeInstantiation(<ConditionalType>type, combineTypeMappers((<ConditionalType>type).mapper, mapper));
}
if (type.flags & TypeFlags.Substitution) {
return mapper((<SubstitutionType>type).typeParameter);
@@ -9691,11 +9704,11 @@ namespace ts {
}
}
if (flags & TypeFlags.Conditional) {
if (result = isRelatedTo((<ConditionalType>source).checkType, (<ConditionalType>target).checkType, /*reportErrors*/ false)) {
if (result &= isRelatedTo((<ConditionalType>source).extendsType, (<ConditionalType>target).extendsType, /*reportErrors*/ false)) {
if (result &= isRelatedTo((<ConditionalType>source).trueType, (<ConditionalType>target).trueType, /*reportErrors*/ false)) {
if (result &= isRelatedTo((<ConditionalType>source).falseType, (<ConditionalType>target).falseType, /*reportErrors*/ false)) {
if (isDistributiveConditionalType(<ConditionalType>source) === isDistributiveConditionalType(<ConditionalType>target)) {
if ((<ConditionalType>source).root.isDistributive === (<ConditionalType>target).root.isDistributive) {
if (result = isRelatedTo((<ConditionalType>source).checkType, (<ConditionalType>target).checkType, /*reportErrors*/ false)) {
if (result &= isRelatedTo((<ConditionalType>source).extendsType, (<ConditionalType>target).extendsType, /*reportErrors*/ false)) {
if (result &= isRelatedTo(getTrueTypeFromConditionalType(<ConditionalType>source), getTrueTypeFromConditionalType(<ConditionalType>target), /*reportErrors*/ false)) {
if (result &= isRelatedTo(getFalseTypeFromConditionalType(<ConditionalType>source), getFalseTypeFromConditionalType(<ConditionalType>target), /*reportErrors*/ false)) {
return result;
}
}
@@ -10085,20 +10098,11 @@ namespace ts {
}
}
else if (source.flags & TypeFlags.Conditional) {
if (relation !== definitelyAssignableRelation) {
const constraint = getConstraintOfDistributiveConditionalType(<ConditionalType>source);
if (constraint) {
if (result = isRelatedTo(constraint, target, reportErrors)) {
errorInfo = saveErrorInfo;
return result;
}
}
}
if (target.flags & TypeFlags.Conditional) {
if (isTypeIdenticalTo((<ConditionalType>source).checkType, (<ConditionalType>target).checkType) &&
isTypeIdenticalTo((<ConditionalType>source).extendsType, (<ConditionalType>target).extendsType)) {
if (result = isRelatedTo((<ConditionalType>source).trueType, (<ConditionalType>target).trueType, reportErrors)) {
result &= isRelatedTo((<ConditionalType>source).falseType, (<ConditionalType>target).falseType, reportErrors);
if (result = isRelatedTo(getTrueTypeFromConditionalType(<ConditionalType>source), getTrueTypeFromConditionalType(<ConditionalType>target), reportErrors)) {
result &= isRelatedTo(getFalseTypeFromConditionalType(<ConditionalType>source), getFalseTypeFromConditionalType(<ConditionalType>target), reportErrors);
}
if (result) {
errorInfo = saveErrorInfo;
@@ -10106,9 +10110,21 @@ namespace ts {
}
}
}
else if (result = isRelatedTo(getDefaultConstraintOfConditionalType(<ConditionalType>source), target, reportErrors)) {
errorInfo = saveErrorInfo;
return result;
else if (relation !== definitelyAssignableRelation) {
const distributiveConstraint = getConstraintOfDistributiveConditionalType(<ConditionalType>source);
if (distributiveConstraint) {
if (result = isRelatedTo(distributiveConstraint, target, reportErrors)) {
errorInfo = saveErrorInfo;
return result;
}
}
const defaultConstraint = getDefaultConstraintOfConditionalType(<ConditionalType>source);
if (defaultConstraint) {
if (result = isRelatedTo(defaultConstraint, target, reportErrors)) {
errorInfo = saveErrorInfo;
return result;
}
}
}
}
else {
@@ -11479,12 +11495,23 @@ namespace ts {
let symbolStack: Symbol[];
let visited: Map<boolean>;
let contravariant = false;
let propagationType: Type;
inferFromTypes(originalSource, originalTarget);
function inferFromTypes(source: Type, target: Type) {
if (!couldContainTypeVariables(target)) {
return;
}
if (source.flags & (TypeFlags.Any | TypeFlags.Never) && source !== silentNeverType) {
// We are inferring from 'any' or 'never'. We want to infer this type for every type parameter
// referenced in the target type, so we record the propagation type and infer from the target
// to itself. Then, as we find candidates we substitute the propagation type.
const savePropagationType = propagationType;
propagationType = source;
inferFromTypes(target, target);
propagationType = savePropagationType;
return;
}
if (source.aliasSymbol && source.aliasTypeArguments && source.aliasSymbol === target.aliasSymbol) {
// Source and target are types originating in the same generic type alias declaration.
// Simply infer from source type arguments to target type arguments.
@@ -11552,11 +11579,12 @@ namespace ts {
inference.priority = priority;
}
if (priority === inference.priority) {
const candidate = propagationType || source;
if (contravariant) {
inference.contraCandidates = append(inference.contraCandidates, source);
inference.contraCandidates = append(inference.contraCandidates, candidate);
}
else {
inference.candidates = append(inference.candidates, source);
inference.candidates = append(inference.candidates, candidate);
}
}
if (!(priority & InferencePriority.ReturnType) && target.flags & TypeFlags.TypeParameter && !isTypeParameterAtTopLevel(originalTarget, <TypeParameter>target)) {
@@ -11599,8 +11627,8 @@ namespace ts {
else if (source.flags & TypeFlags.Conditional && target.flags & TypeFlags.Conditional) {
inferFromTypes((<ConditionalType>source).checkType, (<ConditionalType>target).checkType);
inferFromTypes((<ConditionalType>source).extendsType, (<ConditionalType>target).extendsType);
inferFromTypes((<ConditionalType>source).trueType, (<ConditionalType>target).trueType);
inferFromTypes((<ConditionalType>source).falseType, (<ConditionalType>target).falseType);
inferFromTypes(getTrueTypeFromConditionalType(<ConditionalType>source), getTrueTypeFromConditionalType(<ConditionalType>target));
inferFromTypes(getFalseTypeFromConditionalType(<ConditionalType>source), getFalseTypeFromConditionalType(<ConditionalType>target));
}
else if (target.flags & TypeFlags.UnionOrIntersection) {
const targetTypes = (<UnionOrIntersectionType>target).types;
@@ -12424,6 +12452,9 @@ namespace ts {
// is a union type, the mapping function is applied to each constituent type and a union
// of the resulting types is returned.
function mapType(type: Type, mapper: (t: Type) => Type, noReductions?: boolean): Type {
if (type.flags & TypeFlags.Never) {
return type;
}
if (!(type.flags & TypeFlags.Union)) {
return mapper(type);
}

View File

@@ -3821,16 +3821,27 @@ namespace ts {
type: InstantiableType | UnionOrIntersectionType;
}
// T extends U ? X : Y (TypeFlags.Conditional)
export interface ConditionalType extends InstantiableType {
export interface ConditionalRoot {
node: ConditionalTypeNode;
checkType: Type;
extendsType: Type;
trueType: Type;
falseType: Type;
/* @internal */
isDistributive: boolean;
inferTypeParameters: TypeParameter[];
/* @internal */
target?: ConditionalType;
outerTypeParameters?: TypeParameter[];
instantiations?: Map<Type>;
aliasSymbol: Symbol;
aliasTypeArguments: Type[];
}
// T extends U ? X : Y (TypeFlags.Conditional)
export interface ConditionalType extends InstantiableType {
root: ConditionalRoot;
checkType: Type;
extendsType: Type;
resolvedTrueType?: Type;
resolvedFalseType?: Type;
/* @internal */
mapper?: TypeMapper;
}

View File

@@ -2192,11 +2192,25 @@ declare namespace ts {
interface IndexType extends InstantiableType {
type: InstantiableType | UnionOrIntersectionType;
}
interface ConditionalType extends InstantiableType {
interface ConditionalRoot {
node: ConditionalTypeNode;
checkType: Type;
extendsType: Type;
trueType: Type;
falseType: Type;
isDistributive: boolean;
inferTypeParameters: TypeParameter[];
outerTypeParameters?: TypeParameter[];
instantiations?: Map<Type>;
aliasSymbol: Symbol;
aliasTypeArguments: Type[];
}
interface ConditionalType extends InstantiableType {
root: ConditionalRoot;
checkType: Type;
extendsType: Type;
resolvedTrueType?: Type;
resolvedFalseType?: Type;
}
interface SubstitutionType extends InstantiableType {
typeParameter: TypeParameter;

View File

@@ -2192,11 +2192,25 @@ declare namespace ts {
interface IndexType extends InstantiableType {
type: InstantiableType | UnionOrIntersectionType;
}
interface ConditionalType extends InstantiableType {
interface ConditionalRoot {
node: ConditionalTypeNode;
checkType: Type;
extendsType: Type;
trueType: Type;
falseType: Type;
isDistributive: boolean;
inferTypeParameters: TypeParameter[];
outerTypeParameters?: TypeParameter[];
instantiations?: Map<Type>;
aliasSymbol: Symbol;
aliasTypeArguments: Type[];
}
interface ConditionalType extends InstantiableType {
root: ConditionalRoot;
checkType: Type;
extendsType: Type;
resolvedTrueType?: Type;
resolvedFalseType?: Type;
}
interface SubstitutionType extends InstantiableType {
typeParameter: TypeParameter;

View File

@@ -157,7 +157,7 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(275,43): error TS
type T20 = TypeName<string | (() => void)>; // "string" | "function"
type T21 = TypeName<any>; // "string" | "number" | "boolean" | "undefined" | "function" | "object"
type T22 = TypeName<never>; // "string" | "number" | "boolean" | "undefined" | "function" | "object"
type T22 = TypeName<never>; // never
type T23 = TypeName<{}>; // "object"
type KnockoutObservable<T> = { object: T };
@@ -329,7 +329,7 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(275,43): error TS
type Q1 = IsString<number>; // false
type Q2 = IsString<"abc">; // true
type Q3 = IsString<any>; // boolean
type Q4 = IsString<never>; // boolean
type Q4 = IsString<never>; // never
type N1 = Not<false>; // true
type N2 = Not<true>; // false
@@ -357,9 +357,9 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(275,43): error TS
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 T42 = never extends number ? true : false; // true
type IsNever<T> = T extends never ? true : false;
type IsNever<T> = [T] extends [never] ? true : false;
type T50 = IsNever<never>; // true
type T51 = IsNever<number>; // false

View File

@@ -64,7 +64,7 @@ type TypeName<T> =
type T20 = TypeName<string | (() => void)>; // "string" | "function"
type T21 = TypeName<any>; // "string" | "number" | "boolean" | "undefined" | "function" | "object"
type T22 = TypeName<never>; // "string" | "number" | "boolean" | "undefined" | "function" | "object"
type T22 = TypeName<never>; // never
type T23 = TypeName<{}>; // "object"
type KnockoutObservable<T> = { object: T };
@@ -172,7 +172,7 @@ 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 Q4 = IsString<never>; // never
type N1 = Not<false>; // true
type N2 = Not<true>; // false
@@ -200,9 +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 T42 = never extends number ? true : false; // true
type IsNever<T> = T extends never ? true : false;
type IsNever<T> = [T] extends [never] ? true : false;
type T50 = IsNever<never>; // true
type T51 = IsNever<number>; // false
@@ -551,7 +551,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 IsNever<T> = [T] extends [never] ? true : false;
declare type T50 = IsNever<never>;
declare type T51 = IsNever<number>;
declare type T52 = IsNever<any>;
@@ -572,7 +572,7 @@ declare type T82 = Eq2<false, true>;
declare type T83 = Eq2<false, false>;
declare type Foo<T> = T extends string ? boolean : number;
declare type Bar<T> = T extends string ? boolean : number;
declare const convert: <U>(value: Foo<U>) => Foo<U>;
declare const convert: <U>(value: Foo<U>) => Bar<U>;
declare type Baz<T> = Foo<T>;
declare const convert2: <T>(value: Foo<T>) => Foo<T>;
declare function f31<T>(): void;

View File

@@ -243,7 +243,7 @@ type T21 = TypeName<any>; // "string" | "number" | "boolean" | "undefined" | "f
>T21 : Symbol(T21, Decl(conditionalTypes1.ts, 63, 43))
>TypeName : Symbol(TypeName, Decl(conditionalTypes1.ts, 53, 43))
type T22 = TypeName<never>; // "string" | "number" | "boolean" | "undefined" | "function" | "object"
type T22 = TypeName<never>; // never
>T22 : Symbol(T22, Decl(conditionalTypes1.ts, 64, 25))
>TypeName : Symbol(TypeName, Decl(conditionalTypes1.ts, 53, 43))
@@ -668,7 +668,7 @@ type Q3 = IsString<any>; // boolean
>Q3 : Symbol(Q3, Decl(conditionalTypes1.ts, 171, 26))
>IsString : Symbol(IsString, Decl(conditionalTypes1.ts, 166, 63))
type Q4 = IsString<never>; // boolean
type Q4 = IsString<never>; // never
>Q4 : Symbol(Q4, Decl(conditionalTypes1.ts, 172, 24))
>IsString : Symbol(IsString, Decl(conditionalTypes1.ts, 166, 63))
@@ -762,16 +762,16 @@ type T40 = never extends never ? true : false; // true
type T41 = number extends never ? true : false; // false
>T41 : Symbol(T41, Decl(conditionalTypes1.ts, 199, 46))
type T42 = never extends number ? true : false; // boolean
type T42 = never extends number ? true : false; // true
>T42 : Symbol(T42, Decl(conditionalTypes1.ts, 200, 47))
type IsNever<T> = T extends never ? true : false;
type IsNever<T> = [T] extends [never] ? true : false;
>IsNever : Symbol(IsNever, Decl(conditionalTypes1.ts, 201, 47))
>T : Symbol(T, Decl(conditionalTypes1.ts, 203, 13))
>T : Symbol(T, Decl(conditionalTypes1.ts, 203, 13))
type T50 = IsNever<never>; // true
>T50 : Symbol(T50, Decl(conditionalTypes1.ts, 203, 49))
>T50 : Symbol(T50, Decl(conditionalTypes1.ts, 203, 53))
>IsNever : Symbol(IsNever, Decl(conditionalTypes1.ts, 201, 47))
type T51 = IsNever<number>; // false

View File

@@ -254,8 +254,8 @@ type T21 = TypeName<any>; // "string" | "number" | "boolean" | "undefined" | "f
>T21 : "string" | "number" | "boolean" | "undefined" | "object" | "function"
>TypeName : TypeName<T>
type T22 = TypeName<never>; // "string" | "number" | "boolean" | "undefined" | "function" | "object"
>T22 : "string" | "number" | "boolean" | "undefined" | "object" | "function"
type T22 = TypeName<never>; // never
>T22 : never
>TypeName : TypeName<T>
type T23 = TypeName<{}>; // "object"
@@ -741,8 +741,8 @@ type Q3 = IsString<any>; // boolean
>Q3 : boolean
>IsString : Extends<T, string>
type Q4 = IsString<never>; // boolean
>Q4 : boolean
type Q4 = IsString<never>; // never
>Q4 : never
>IsString : Extends<T, string>
type N1 = Not<false>; // true
@@ -865,12 +865,12 @@ type T41 = number extends never ? true : false; // false
>true : true
>false : false
type T42 = never extends number ? true : false; // boolean
>T42 : boolean
type T42 = never extends number ? true : false; // true
>T42 : true
>true : true
>false : false
type IsNever<T> = T extends never ? true : false;
type IsNever<T> = [T] extends [never] ? true : false;
>IsNever : IsNever<T>
>T : T
>T : T
@@ -1010,8 +1010,8 @@ type Bar<T> = T extends string ? boolean : number;
>T : T
const convert = <U>(value: Foo<U>): Bar<U> => value;
>convert : <U>(value: Foo<U>) => Foo<U>
><U>(value: Foo<U>): Bar<U> => value : <U>(value: Foo<U>) => Foo<U>
>convert : <U>(value: Foo<U>) => Bar<U>
><U>(value: Foo<U>): Bar<U> => value : <U>(value: Foo<U>) => Bar<U>
>U : U
>value : Foo<U>
>Foo : Foo<T>
@@ -1095,7 +1095,7 @@ function f33<T, U>() {
>U : U
type T2 = Bar<T & U>;
>T2 : Foo<T & U>
>T2 : Bar<T & U>
>Bar : Bar<T>
>T : T
>U : U
@@ -1106,7 +1106,7 @@ function f33<T, U>() {
var z: T2;
>z : Foo<T & U>
>T2 : Foo<T & U>
>T2 : Bar<T & U>
}
// Repro from #21823
@@ -1236,7 +1236,7 @@ function f50() {
>T : T
type Omit<T extends object> = { [P in keyof T]: If<Eq<T[P], never>, never, P>; }[keyof T];
>Omit : { [P in keyof T]: (T[P] extends never ? boolean : false) extends false ? P : never; }[keyof T]
>Omit : { [P in keyof T]: (T[P] extends never ? never : false) extends false ? P : never; }[keyof T]
>T : T
>P : P
>T : T
@@ -1263,7 +1263,7 @@ function f50() {
type A = Omit<{ a: void; b: never; }>; // 'a'
>A : "a"
>Omit : { [P in keyof T]: (T[P] extends never ? boolean : false) extends false ? P : never; }[keyof T]
>Omit : { [P in keyof T]: (T[P] extends never ? never : false) extends false ? P : never; }[keyof T]
>a : void
>b : never

View File

@@ -50,7 +50,7 @@ tests/cases/conformance/types/conditional/inferTypes1.ts(134,40): error TS2322:
type T13 = ReturnType<(<T extends U, U extends number[]>() => T)>; // number[]
type T14 = ReturnType<typeof f1>; // { a: number, b: string }
type T15 = ReturnType<any>; // any
type T16 = ReturnType<never>; // any
type T16 = ReturnType<never>; // never
type T17 = ReturnType<string>; // Error
~~~~~~
!!! error TS2344: Type 'string' does not satisfy the constraint '(...args: any[]) => any'.
@@ -61,7 +61,7 @@ tests/cases/conformance/types/conditional/inferTypes1.ts(134,40): error TS2322:
type U10 = InstanceType<typeof C>; // C
type U11 = InstanceType<any>; // any
type U12 = InstanceType<never>; // any
type U12 = InstanceType<never>; // never
type U13 = InstanceType<string>; // Error
~~~~~~
!!! error TS2344: Type 'string' does not satisfy the constraint 'new (...args: any[]) => any'.
@@ -72,7 +72,7 @@ tests/cases/conformance/types/conditional/inferTypes1.ts(134,40): error TS2322:
type ArgumentType<T extends (x: any) => any> = T extends (a: infer A) => any ? A : any;
type T20 = ArgumentType<() => void>; // never
type T20 = ArgumentType<() => void>; // {}
type T21 = ArgumentType<(x: string) => number>; // string
type T22 = ArgumentType<(x?: string) => number>; // string | undefined
type T23 = ArgumentType<(...args: string[]) => number>; // string
@@ -84,7 +84,7 @@ tests/cases/conformance/types/conditional/inferTypes1.ts(134,40): error TS2322:
!!! error TS2344: Type 'Function' does not satisfy the constraint '(x: any) => any'.
!!! error TS2344: Type 'Function' provides no match for the signature '(x: any): any'.
type T26 = ArgumentType<any>; // any
type T27 = ArgumentType<never>; // any
type T27 = ArgumentType<never>; // never
type X1<T extends { x: any, y: any }> = T extends { x: infer X, y: infer Y } ? [X, Y] : any;

View File

@@ -28,26 +28,26 @@ type T12 = ReturnType<(<T>() => T)>; // {}
type T13 = ReturnType<(<T extends U, U extends number[]>() => T)>; // number[]
type T14 = ReturnType<typeof f1>; // { a: number, b: string }
type T15 = ReturnType<any>; // any
type T16 = ReturnType<never>; // any
type T16 = ReturnType<never>; // never
type T17 = ReturnType<string>; // Error
type T18 = ReturnType<Function>; // Error
type U10 = InstanceType<typeof C>; // C
type U11 = InstanceType<any>; // any
type U12 = InstanceType<never>; // any
type U12 = InstanceType<never>; // never
type U13 = InstanceType<string>; // Error
type U14 = InstanceType<Function>; // Error
type ArgumentType<T extends (x: any) => any> = T extends (a: infer A) => any ? A : any;
type T20 = ArgumentType<() => void>; // never
type T20 = ArgumentType<() => void>; // {}
type T21 = ArgumentType<(x: string) => number>; // string
type T22 = ArgumentType<(x?: string) => number>; // string | undefined
type T23 = ArgumentType<(...args: string[]) => number>; // string
type T24 = ArgumentType<(x: string, y: string) => number>; // Error
type T25 = ArgumentType<Function>; // Error
type T26 = ArgumentType<any>; // any
type T27 = ArgumentType<never>; // any
type T27 = ArgumentType<never>; // never
type X1<T extends { x: any, y: any }> = T extends { x: infer X, y: infer Y } ? [X, Y] : any;

View File

@@ -106,7 +106,7 @@ type T15 = ReturnType<any>; // any
>T15 : Symbol(T15, Decl(inferTypes1.ts, 27, 33))
>ReturnType : Symbol(ReturnType, Decl(lib.d.ts, --, --))
type T16 = ReturnType<never>; // any
type T16 = ReturnType<never>; // never
>T16 : Symbol(T16, Decl(inferTypes1.ts, 28, 27))
>ReturnType : Symbol(ReturnType, Decl(lib.d.ts, --, --))
@@ -128,7 +128,7 @@ type U11 = InstanceType<any>; // any
>U11 : Symbol(U11, Decl(inferTypes1.ts, 33, 34))
>InstanceType : Symbol(InstanceType, Decl(lib.d.ts, --, --))
type U12 = InstanceType<never>; // any
type U12 = InstanceType<never>; // never
>U12 : Symbol(U12, Decl(inferTypes1.ts, 34, 29))
>InstanceType : Symbol(InstanceType, Decl(lib.d.ts, --, --))
@@ -150,7 +150,7 @@ type ArgumentType<T extends (x: any) => any> = T extends (a: infer A) => any ? A
>A : Symbol(A, Decl(inferTypes1.ts, 39, 66))
>A : Symbol(A, Decl(inferTypes1.ts, 39, 66))
type T20 = ArgumentType<() => void>; // never
type T20 = ArgumentType<() => void>; // {}
>T20 : Symbol(T20, Decl(inferTypes1.ts, 39, 87))
>ArgumentType : Symbol(ArgumentType, Decl(inferTypes1.ts, 37, 34))
@@ -184,7 +184,7 @@ type T26 = ArgumentType<any>; // any
>T26 : Symbol(T26, Decl(inferTypes1.ts, 46, 34))
>ArgumentType : Symbol(ArgumentType, Decl(inferTypes1.ts, 37, 34))
type T27 = ArgumentType<never>; // any
type T27 = ArgumentType<never>; // never
>T27 : Symbol(T27, Decl(inferTypes1.ts, 47, 29))
>ArgumentType : Symbol(ArgumentType, Decl(inferTypes1.ts, 37, 34))

View File

@@ -110,8 +110,8 @@ type T15 = ReturnType<any>; // any
>T15 : any
>ReturnType : ReturnType<T>
type T16 = ReturnType<never>; // any
>T16 : any
type T16 = ReturnType<never>; // never
>T16 : never
>ReturnType : ReturnType<T>
type T17 = ReturnType<string>; // Error
@@ -132,8 +132,8 @@ type U11 = InstanceType<any>; // any
>U11 : any
>InstanceType : InstanceType<T>
type U12 = InstanceType<never>; // any
>U12 : any
type U12 = InstanceType<never>; // never
>U12 : never
>InstanceType : InstanceType<T>
type U13 = InstanceType<string>; // Error
@@ -154,8 +154,8 @@ type ArgumentType<T extends (x: any) => any> = T extends (a: infer A) => any ? A
>A : A
>A : A
type T20 = ArgumentType<() => void>; // never
>T20 : never
type T20 = ArgumentType<() => void>; // {}
>T20 : {}
>ArgumentType : ArgumentType<T>
type T21 = ArgumentType<(x: string) => number>; // string
@@ -188,8 +188,8 @@ type T26 = ArgumentType<any>; // any
>T26 : any
>ArgumentType : ArgumentType<T>
type T27 = ArgumentType<never>; // any
>T27 : any
type T27 = ArgumentType<never>; // never
>T27 : never
>ArgumentType : ArgumentType<T>
type X1<T extends { x: any, y: any }> = T extends { x: infer X, y: infer Y } ? [X, Y] : any;
@@ -312,7 +312,7 @@ type T60 = infer U; // Error
>U : U
type T61<T> = infer A extends infer B ? infer C : infer D; // Error
>T61 : never
>T61 : {}
>T : T
>A : A
>B : B

File diff suppressed because one or more lines are too long

View File

@@ -66,7 +66,7 @@ type TypeName<T> =
type T20 = TypeName<string | (() => void)>; // "string" | "function"
type T21 = TypeName<any>; // "string" | "number" | "boolean" | "undefined" | "function" | "object"
type T22 = TypeName<never>; // "string" | "number" | "boolean" | "undefined" | "function" | "object"
type T22 = TypeName<never>; // never
type T23 = TypeName<{}>; // "object"
type KnockoutObservable<T> = { object: T };
@@ -174,7 +174,7 @@ 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 Q4 = IsString<never>; // never
type N1 = Not<false>; // true
type N2 = Not<true>; // false
@@ -202,9 +202,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 T42 = never extends number ? true : false; // true
type IsNever<T> = T extends never ? true : false;
type IsNever<T> = [T] extends [never] ? true : false;
type T50 = IsNever<never>; // true
type T51 = IsNever<number>; // false

View File

@@ -30,26 +30,26 @@ type T12 = ReturnType<(<T>() => T)>; // {}
type T13 = ReturnType<(<T extends U, U extends number[]>() => T)>; // number[]
type T14 = ReturnType<typeof f1>; // { a: number, b: string }
type T15 = ReturnType<any>; // any
type T16 = ReturnType<never>; // any
type T16 = ReturnType<never>; // never
type T17 = ReturnType<string>; // Error
type T18 = ReturnType<Function>; // Error
type U10 = InstanceType<typeof C>; // C
type U11 = InstanceType<any>; // any
type U12 = InstanceType<never>; // any
type U12 = InstanceType<never>; // never
type U13 = InstanceType<string>; // Error
type U14 = InstanceType<Function>; // Error
type ArgumentType<T extends (x: any) => any> = T extends (a: infer A) => any ? A : any;
type T20 = ArgumentType<() => void>; // never
type T20 = ArgumentType<() => void>; // {}
type T21 = ArgumentType<(x: string) => number>; // string
type T22 = ArgumentType<(x?: string) => number>; // string | undefined
type T23 = ArgumentType<(...args: string[]) => number>; // string
type T24 = ArgumentType<(x: string, y: string) => number>; // Error
type T25 = ArgumentType<Function>; // Error
type T26 = ArgumentType<any>; // any
type T27 = ArgumentType<never>; // any
type T27 = ArgumentType<never>; // never
type X1<T extends { x: any, y: any }> = T extends { x: infer X, y: infer Y } ? [X, Y] : any;