Preserve literal types in contextual unions (#19966)
* Cherrypick non-comparability related changes from prolific literals PR * Renames and other style changes * Accept changes to new tests * Exclude the domain root from contextual typing literals except for type variables * Readd simple preservation fix * Add huge map test * Revert changes to widening on destructuring initalizers * Use tristate for subtype-reduction type * Rename type and argument * Move longer-running test to user suite
This commit is contained in:
parent
d01f4d140a
commit
eba15b5990
|
@ -4338,7 +4338,7 @@ namespace ts {
|
|||
type = getTypeWithFacts(type, TypeFacts.NEUndefined);
|
||||
}
|
||||
return declaration.initializer ?
|
||||
getUnionType([type, checkExpressionCached(declaration.initializer)], /*subtypeReduction*/ true) :
|
||||
getUnionType([type, checkExpressionCached(declaration.initializer)], UnionReduction.Subtype) :
|
||||
type;
|
||||
}
|
||||
|
||||
|
@ -4506,7 +4506,7 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
const type = jsDocType || getUnionType(types, /*subtypeReduction*/ true);
|
||||
const type = jsDocType || getUnionType(types, UnionReduction.Subtype);
|
||||
return getWidenedType(addOptionality(type, definedInMethod && !definedInConstructor));
|
||||
}
|
||||
|
||||
|
@ -5339,7 +5339,7 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
if (memberTypeList.length) {
|
||||
const enumType = getUnionType(memberTypeList, /*subtypeReduction*/ false, symbol, /*aliasTypeArguments*/ undefined);
|
||||
const enumType = getUnionType(memberTypeList, UnionReduction.Literal, symbol, /*aliasTypeArguments*/ undefined);
|
||||
if (enumType.flags & TypeFlags.Union) {
|
||||
enumType.flags |= TypeFlags.EnumLiteral;
|
||||
enumType.symbol = symbol;
|
||||
|
@ -5902,7 +5902,7 @@ namespace ts {
|
|||
if (unionSignatures.length > 1) {
|
||||
let thisParameter = signature.thisParameter;
|
||||
if (forEach(unionSignatures, sig => sig.thisParameter)) {
|
||||
const thisType = getUnionType(map(unionSignatures, sig => getTypeOfSymbol(sig.thisParameter) || anyType), /*subtypeReduction*/ true);
|
||||
const thisType = getUnionType(map(unionSignatures, sig => getTypeOfSymbol(sig.thisParameter) || anyType), UnionReduction.Subtype);
|
||||
thisParameter = createSymbolWithType(signature.thisParameter, thisType);
|
||||
}
|
||||
s = cloneSignature(signature);
|
||||
|
@ -5928,7 +5928,7 @@ namespace ts {
|
|||
indexTypes.push(indexInfo.type);
|
||||
isAnyReadonly = isAnyReadonly || indexInfo.isReadonly;
|
||||
}
|
||||
return createIndexInfo(getUnionType(indexTypes, /*subtypeReduction*/ true), isAnyReadonly);
|
||||
return createIndexInfo(getUnionType(indexTypes, UnionReduction.Subtype), isAnyReadonly);
|
||||
}
|
||||
|
||||
function resolveUnionTypeMembers(type: UnionType) {
|
||||
|
@ -6616,7 +6616,7 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
if (propTypes.length) {
|
||||
return getUnionType(propTypes, /*subtypeReduction*/ true);
|
||||
return getUnionType(propTypes, UnionReduction.Subtype);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
|
@ -7003,7 +7003,7 @@ namespace ts {
|
|||
type = instantiateType(getReturnTypeOfSignature(signature.target), signature.mapper);
|
||||
}
|
||||
else if (signature.unionSignatures) {
|
||||
type = getUnionType(map(signature.unionSignatures, getReturnTypeOfSignature), /*subtypeReduction*/ true);
|
||||
type = getUnionType(map(signature.unionSignatures, getReturnTypeOfSignature), UnionReduction.Subtype);
|
||||
}
|
||||
else {
|
||||
type = getReturnTypeFromBody(<FunctionLikeDeclaration>signature.declaration);
|
||||
|
@ -7845,7 +7845,7 @@ namespace ts {
|
|||
// expression constructs such as array literals and the || and ?: operators). Named types can
|
||||
// circularly reference themselves and therefore cannot be subtype reduced during their declaration.
|
||||
// For example, "type Item = string | (() => Item" is a named type that circularly references itself.
|
||||
function getUnionType(types: Type[], subtypeReduction?: boolean, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type {
|
||||
function getUnionType(types: Type[], unionReduction: UnionReduction = UnionReduction.Literal, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type {
|
||||
if (types.length === 0) {
|
||||
return neverType;
|
||||
}
|
||||
|
@ -7857,11 +7857,15 @@ namespace ts {
|
|||
if (typeSet.containsAny) {
|
||||
return anyType;
|
||||
}
|
||||
if (subtypeReduction) {
|
||||
removeSubtypes(typeSet);
|
||||
}
|
||||
else if (typeSet.containsLiteralOrUniqueESSymbol) {
|
||||
removeRedundantLiteralTypes(typeSet);
|
||||
switch (unionReduction) {
|
||||
case UnionReduction.Literal:
|
||||
if (typeSet.containsLiteralOrUniqueESSymbol) {
|
||||
removeRedundantLiteralTypes(typeSet);
|
||||
}
|
||||
break;
|
||||
case UnionReduction.Subtype:
|
||||
removeSubtypes(typeSet);
|
||||
break;
|
||||
}
|
||||
if (typeSet.length === 0) {
|
||||
return typeSet.containsNull ? typeSet.containsNonWideningType ? nullType : nullWideningType :
|
||||
|
@ -7937,7 +7941,7 @@ namespace ts {
|
|||
function getTypeFromUnionTypeNode(node: UnionTypeNode): Type {
|
||||
const links = getNodeLinks(node);
|
||||
if (!links.resolvedType) {
|
||||
links.resolvedType = getUnionType(map(node.types, getTypeFromTypeNode), /*subtypeReduction*/ false,
|
||||
links.resolvedType = getUnionType(map(node.types, getTypeFromTypeNode), UnionReduction.Literal,
|
||||
getAliasSymbolForTypeNode(node), getAliasTypeArgumentsForTypeNode(node));
|
||||
}
|
||||
return links.resolvedType;
|
||||
|
@ -8012,7 +8016,7 @@ namespace ts {
|
|||
// the form X & A & Y | X & B & Y and recursively reduce until no union type constituents remain.
|
||||
const unionType = <UnionType>typeSet[unionIndex];
|
||||
return getUnionType(map(unionType.types, t => getIntersectionType(replaceElement(typeSet, unionIndex, t))),
|
||||
/*subtypeReduction*/ false, aliasSymbol, aliasTypeArguments);
|
||||
UnionReduction.Literal, aliasSymbol, aliasTypeArguments);
|
||||
}
|
||||
const id = getTypeListId(typeSet);
|
||||
let type = intersectionTypes.get(id);
|
||||
|
@ -8851,7 +8855,7 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
if (type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Primitive)) {
|
||||
return getUnionType(instantiateTypes((<UnionType>type).types, mapper), /*subtypeReduction*/ false, type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper));
|
||||
return getUnionType(instantiateTypes((<UnionType>type).types, mapper), UnionReduction.Literal, type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper));
|
||||
}
|
||||
if (type.flags & TypeFlags.Intersection) {
|
||||
return getIntersectionType(instantiateTypes((<IntersectionType>type).types, mapper), type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper));
|
||||
|
@ -10713,7 +10717,7 @@ namespace ts {
|
|||
const primaryTypes = filter(types, t => !(t.flags & TypeFlags.Nullable));
|
||||
return primaryTypes.length ?
|
||||
getNullableType(getSupertypeOrUnion(primaryTypes), getFalsyFlagsOfTypes(types) & TypeFlags.Nullable) :
|
||||
getUnionType(types, /*subtypeReduction*/ true);
|
||||
getUnionType(types, UnionReduction.Subtype);
|
||||
}
|
||||
|
||||
// Return the leftmost type for which no type to the right is a subtype.
|
||||
|
@ -11004,7 +11008,7 @@ namespace ts {
|
|||
// Widening an empty object literal transitions from a highly restrictive type to
|
||||
// a highly inclusive one. For that reason we perform subtype reduction here if the
|
||||
// union includes empty object types (e.g. reducing {} | string to just {}).
|
||||
return getUnionType(widenedTypes, some(widenedTypes, isEmptyObjectType));
|
||||
return getUnionType(widenedTypes, some(widenedTypes, isEmptyObjectType) ? UnionReduction.Subtype : UnionReduction.Literal);
|
||||
}
|
||||
if (isArrayType(type) || isTupleType(type)) {
|
||||
return createTypeReference((<TypeReference>type).target, sameMap((<TypeReference>type).typeArguments, getWidenedType));
|
||||
|
@ -11251,7 +11255,7 @@ namespace ts {
|
|||
function inferTargetType(sourceType: Type): Type {
|
||||
inference.candidates = undefined;
|
||||
inferTypes(inferences, sourceType, templateType, 0, mappedTypeStack);
|
||||
return inference.candidates ? getUnionType(inference.candidates, /*subtypeReduction*/ true) : emptyObjectType;
|
||||
return inference.candidates ? getUnionType(inference.candidates, UnionReduction.Subtype) : emptyObjectType;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11610,7 +11614,7 @@ namespace ts {
|
|||
if (candidates.length > 1) {
|
||||
const objectLiterals = filter(candidates, isObjectLiteralType);
|
||||
if (objectLiterals.length) {
|
||||
const objectLiteralsType = getWidenedType(getUnionType(objectLiterals, /*subtypeReduction*/ true));
|
||||
const objectLiteralsType = getWidenedType(getUnionType(objectLiterals, UnionReduction.Subtype));
|
||||
return concatenate(filter(candidates, t => !isObjectLiteralType(t)), [objectLiteralsType]);
|
||||
}
|
||||
}
|
||||
|
@ -11637,7 +11641,7 @@ namespace ts {
|
|||
// union types were requested or if all inferences were made from the return type position, infer a
|
||||
// union type. Otherwise, infer a common supertype.
|
||||
const unwidenedType = inference.priority & InferencePriority.Contravariant ? getCommonSubtype(baseCandidates) :
|
||||
context.flags & InferenceFlags.InferUnionTypes || inference.priority & InferencePriority.ReturnType ? getUnionType(baseCandidates, /*subtypeReduction*/ true) :
|
||||
context.flags & InferenceFlags.InferUnionTypes || inference.priority & InferencePriority.ReturnType ? getUnionType(baseCandidates, UnionReduction.Subtype) :
|
||||
getCommonSupertype(baseCandidates);
|
||||
inferredType = getWidenedType(unwidenedType);
|
||||
}
|
||||
|
@ -12211,7 +12215,7 @@ namespace ts {
|
|||
// Apply a mapping function to a type and return the resulting type. If the source type
|
||||
// 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): Type {
|
||||
function mapType(type: Type, mapper: (t: Type) => Type, noReductions?: boolean): Type {
|
||||
if (!(type.flags & TypeFlags.Union)) {
|
||||
return mapper(type);
|
||||
}
|
||||
|
@ -12232,7 +12236,7 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
}
|
||||
return mappedTypes ? getUnionType(mappedTypes) : mappedType;
|
||||
return mappedTypes ? getUnionType(mappedTypes, noReductions ? UnionReduction.None : UnionReduction.Literal) : mappedType;
|
||||
}
|
||||
|
||||
function extractTypesOfKind(type: Type, kind: TypeFlags) {
|
||||
|
@ -12291,7 +12295,7 @@ namespace ts {
|
|||
return elementType.flags & TypeFlags.Never ?
|
||||
autoArrayType :
|
||||
createArrayType(elementType.flags & TypeFlags.Union ?
|
||||
getUnionType((<UnionType>elementType).types, /*subtypeReduction*/ true) :
|
||||
getUnionType((<UnionType>elementType).types, UnionReduction.Subtype) :
|
||||
elementType);
|
||||
}
|
||||
|
||||
|
@ -12324,7 +12328,7 @@ namespace ts {
|
|||
// At flow control branch or loop junctions, if the type along every antecedent code path
|
||||
// is an evolving array type, we construct a combined evolving array type. Otherwise we
|
||||
// finalize all evolving array types.
|
||||
function getUnionOrEvolvingArrayType(types: Type[], subtypeReduction: boolean) {
|
||||
function getUnionOrEvolvingArrayType(types: Type[], subtypeReduction: UnionReduction) {
|
||||
return isEvolvingArrayTypeList(types) ?
|
||||
getEvolvingArrayType(getUnionType(map(types, getElementTypeOfEvolvingArrayType))) :
|
||||
getUnionType(sameMap(types, finalizeEvolvingArrayType), subtypeReduction);
|
||||
|
@ -12616,7 +12620,7 @@ namespace ts {
|
|||
seenIncomplete = true;
|
||||
}
|
||||
}
|
||||
return createFlowType(getUnionOrEvolvingArrayType(antecedentTypes, subtypeReduction), seenIncomplete);
|
||||
return createFlowType(getUnionOrEvolvingArrayType(antecedentTypes, subtypeReduction ? UnionReduction.Subtype : UnionReduction.Literal), seenIncomplete);
|
||||
}
|
||||
|
||||
function getTypeAtFlowLoopLabel(flow: FlowLabel): FlowType {
|
||||
|
@ -12645,7 +12649,7 @@ namespace ts {
|
|||
// path that leads to the top.
|
||||
for (let i = flowLoopStart; i < flowLoopCount; i++) {
|
||||
if (flowLoopNodes[i] === flow && flowLoopKeys[i] === key && flowLoopTypes[i].length) {
|
||||
return createFlowType(getUnionOrEvolvingArrayType(flowLoopTypes[i], /*subtypeReduction*/ false), /*incomplete*/ true);
|
||||
return createFlowType(getUnionOrEvolvingArrayType(flowLoopTypes[i], UnionReduction.Literal), /*incomplete*/ true);
|
||||
}
|
||||
}
|
||||
// Add the flow loop junction and reference to the in-process stack and analyze
|
||||
|
@ -12687,7 +12691,7 @@ namespace ts {
|
|||
}
|
||||
// The result is incomplete if the first antecedent (the non-looping control flow path)
|
||||
// is incomplete.
|
||||
const result = getUnionOrEvolvingArrayType(antecedentTypes, subtypeReduction);
|
||||
const result = getUnionOrEvolvingArrayType(antecedentTypes, subtypeReduction ? UnionReduction.Subtype : UnionReduction.Literal);
|
||||
if (isIncomplete(firstAntecedentType)) {
|
||||
return createFlowType(result, /*incomplete*/ true);
|
||||
}
|
||||
|
@ -14052,11 +14056,11 @@ namespace ts {
|
|||
return mapType(type, t => {
|
||||
const prop = t.flags & TypeFlags.StructuredType ? getPropertyOfType(t, name) : undefined;
|
||||
return prop ? getTypeOfSymbol(prop) : undefined;
|
||||
});
|
||||
}, /*noReductions*/ true);
|
||||
}
|
||||
|
||||
function getIndexTypeOfContextualType(type: Type, kind: IndexKind) {
|
||||
return mapType(type, t => getIndexTypeOfStructuredType(t, kind));
|
||||
return mapType(type, t => getIndexTypeOfStructuredType(t, kind), /*noReductions*/ true);
|
||||
}
|
||||
|
||||
// Return true if the given contextual type is a tuple-like type
|
||||
|
@ -14463,7 +14467,7 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
return createArrayType(elementTypes.length ?
|
||||
getUnionType(elementTypes, /*subtypeReduction*/ true) :
|
||||
getUnionType(elementTypes, UnionReduction.Subtype) :
|
||||
strictNullChecks ? implicitNeverType : undefinedWideningType);
|
||||
}
|
||||
|
||||
|
@ -14542,7 +14546,7 @@ namespace ts {
|
|||
propTypes.push(getTypeOfSymbol(properties[i]));
|
||||
}
|
||||
}
|
||||
const unionType = propTypes.length ? getUnionType(propTypes, /*subtypeReduction*/ true) : undefinedType;
|
||||
const unionType = propTypes.length ? getUnionType(propTypes, UnionReduction.Subtype) : undefinedType;
|
||||
return createIndexInfo(unionType, /*isReadonly*/ false);
|
||||
}
|
||||
|
||||
|
@ -14889,7 +14893,7 @@ namespace ts {
|
|||
const childrenPropSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, jsxChildrenPropertyName);
|
||||
childrenPropSymbol.type = childrenTypes.length === 1 ?
|
||||
childrenTypes[0] :
|
||||
createArrayType(getUnionType(childrenTypes, /*subtypeReduction*/ false));
|
||||
createArrayType(getUnionType(childrenTypes));
|
||||
attributesTable.set(jsxChildrenPropertyName, childrenPropSymbol);
|
||||
}
|
||||
}
|
||||
|
@ -15025,7 +15029,7 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
return getUnionType(map(instantiatedSignatures, getReturnTypeOfSignature), /*subtypeReduction*/ true);
|
||||
return getUnionType(map(instantiatedSignatures, getReturnTypeOfSignature), UnionReduction.Subtype);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -15217,7 +15221,7 @@ namespace ts {
|
|||
const types = (elementType as UnionType).types;
|
||||
return getUnionType(types.map(type => {
|
||||
return resolveCustomJsxElementAttributesType(openingLikeElement, shouldIncludeAllStatelessAttributesType, type, elementClassType);
|
||||
}), /*subtypeReduction*/ true);
|
||||
}), UnionReduction.Subtype);
|
||||
}
|
||||
|
||||
// If the elemType is a string type, we have to return anyType to prevent an error downstream as we will try to find construct or call signature of the type
|
||||
|
@ -17968,7 +17972,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
// Return a union of the return expression types.
|
||||
type = getUnionType(types, /*subtypeReduction*/ true);
|
||||
type = getUnionType(types, UnionReduction.Subtype);
|
||||
}
|
||||
|
||||
if (!contextualSignature) {
|
||||
|
@ -18876,7 +18880,7 @@ namespace ts {
|
|||
leftType;
|
||||
case SyntaxKind.BarBarToken:
|
||||
return getTypeFacts(leftType) & TypeFacts.Falsy ?
|
||||
getUnionType([removeDefinitelyFalsyTypes(leftType), rightType], /*subtypeReduction*/ true) :
|
||||
getUnionType([removeDefinitelyFalsyTypes(leftType), rightType], UnionReduction.Subtype) :
|
||||
leftType;
|
||||
case SyntaxKind.EqualsToken:
|
||||
checkAssignmentOperator(rightType);
|
||||
|
@ -19036,7 +19040,7 @@ namespace ts {
|
|||
checkExpression(node.condition);
|
||||
const type1 = checkExpression(node.whenTrue, checkMode);
|
||||
const type2 = checkExpression(node.whenFalse, checkMode);
|
||||
return getUnionType([type1, type2], /*subtypeReduction*/ true);
|
||||
return getUnionType([type1, type2], UnionReduction.Subtype);
|
||||
}
|
||||
|
||||
function checkTemplateExpression(node: TemplateExpression): Type {
|
||||
|
@ -20477,7 +20481,7 @@ namespace ts {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
return typeAsPromise.promisedTypeOfPromise = getUnionType(map(onfulfilledParameterSignatures, getTypeOfFirstParameterOfSignature), /*subtypeReduction*/ true);
|
||||
return typeAsPromise.promisedTypeOfPromise = getUnionType(map(onfulfilledParameterSignatures, getTypeOfFirstParameterOfSignature), UnionReduction.Subtype);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -21908,7 +21912,7 @@ namespace ts {
|
|||
const arrayTypes = (<UnionType>inputType).types;
|
||||
const filteredTypes = filter(arrayTypes, t => !(t.flags & TypeFlags.StringLike));
|
||||
if (filteredTypes !== arrayTypes) {
|
||||
arrayType = getUnionType(filteredTypes, /*subtypeReduction*/ true);
|
||||
arrayType = getUnionType(filteredTypes, UnionReduction.Subtype);
|
||||
}
|
||||
}
|
||||
else if (arrayType.flags & TypeFlags.StringLike) {
|
||||
|
@ -21958,7 +21962,7 @@ namespace ts {
|
|||
return stringType;
|
||||
}
|
||||
|
||||
return getUnionType([arrayElementType, stringType], /*subtypeReduction*/ true);
|
||||
return getUnionType([arrayElementType, stringType], UnionReduction.Subtype);
|
||||
}
|
||||
|
||||
return arrayElementType;
|
||||
|
@ -22056,7 +22060,7 @@ namespace ts {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
const returnType = getUnionType(map(signatures, getReturnTypeOfSignature), /*subtypeReduction*/ true);
|
||||
const returnType = getUnionType(map(signatures, getReturnTypeOfSignature), UnionReduction.Subtype);
|
||||
const iteratedType = getIteratedTypeOfIterator(returnType, errorNode, /*isAsyncIterator*/ !!asyncMethodType);
|
||||
if (checkAssignability && errorNode && iteratedType) {
|
||||
// If `checkAssignability` was specified, we were called from
|
||||
|
@ -22131,7 +22135,7 @@ namespace ts {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
let nextResult = getUnionType(map(nextMethodSignatures, getReturnTypeOfSignature), /*subtypeReduction*/ true);
|
||||
let nextResult = getUnionType(map(nextMethodSignatures, getReturnTypeOfSignature), UnionReduction.Subtype);
|
||||
if (isTypeAny(nextResult)) {
|
||||
return undefined;
|
||||
}
|
||||
|
|
|
@ -2787,7 +2787,7 @@ namespace ts {
|
|||
/* @internal */ getNullType(): Type;
|
||||
/* @internal */ getESSymbolType(): Type;
|
||||
/* @internal */ getNeverType(): Type;
|
||||
/* @internal */ getUnionType(types: Type[], subtypeReduction?: boolean): Type;
|
||||
/* @internal */ getUnionType(types: Type[], subtypeReduction?: UnionReduction): Type;
|
||||
/* @internal */ createArrayType(elementType: Type): Type;
|
||||
/* @internal */ createPromiseType(type: Type): Type;
|
||||
|
||||
|
@ -2842,6 +2842,13 @@ namespace ts {
|
|||
/* @internal */ getAccessibleSymbolChain(symbol: Symbol, enclosingDeclaration: Node | undefined, meaning: SymbolFlags, useOnlyExternalAliasing: boolean): Symbol[] | undefined;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export const enum UnionReduction {
|
||||
None = 0,
|
||||
Literal,
|
||||
Subtype
|
||||
}
|
||||
|
||||
export enum NodeBuilderFlags {
|
||||
None = 0,
|
||||
// Options
|
||||
|
|
|
@ -305,7 +305,7 @@ namespace ts.codefix {
|
|||
}
|
||||
}
|
||||
if (types.length) {
|
||||
const type = checker.getWidenedType(checker.getUnionType(types, /*subtypeReduction*/ true));
|
||||
const type = checker.getWidenedType(checker.getUnionType(types, UnionReduction.Subtype));
|
||||
paramTypes[parameterIndex] = isRestParameter ? checker.createArrayType(type) : type;
|
||||
}
|
||||
}
|
||||
|
@ -542,12 +542,12 @@ namespace ts.codefix {
|
|||
return checker.getStringType();
|
||||
}
|
||||
else if (usageContext.candidateTypes) {
|
||||
return checker.getWidenedType(checker.getUnionType(map(usageContext.candidateTypes, t => checker.getBaseTypeOfLiteralType(t)), /*subtypeReduction*/ true));
|
||||
return checker.getWidenedType(checker.getUnionType(map(usageContext.candidateTypes, t => checker.getBaseTypeOfLiteralType(t)), UnionReduction.Subtype));
|
||||
}
|
||||
else if (usageContext.properties && hasCallContext(usageContext.properties.get("then" as __String))) {
|
||||
const paramType = getParameterTypeFromCallContexts(0, usageContext.properties.get("then" as __String).callContexts, /*isRestParameter*/ false, checker);
|
||||
const types = paramType.getCallSignatures().map(c => c.getReturnType());
|
||||
return checker.createPromiseType(types.length ? checker.getUnionType(types, /*subtypeReduction*/ true) : checker.getAnyType());
|
||||
return checker.createPromiseType(types.length ? checker.getUnionType(types, UnionReduction.Subtype) : checker.getAnyType());
|
||||
}
|
||||
else if (usageContext.properties && hasCallContext(usageContext.properties.get("push" as __String))) {
|
||||
return checker.createArrayType(getParameterTypeFromCallContexts(0, usageContext.properties.get("push" as __String).callContexts, /*isRestParameter*/ false, checker));
|
||||
|
@ -610,7 +610,7 @@ namespace ts.codefix {
|
|||
}
|
||||
|
||||
if (types.length) {
|
||||
const type = checker.getWidenedType(checker.getUnionType(types, /*subtypeReduction*/ true));
|
||||
const type = checker.getWidenedType(checker.getUnionType(types, UnionReduction.Subtype));
|
||||
return isRestParameter ? checker.createArrayType(type) : type;
|
||||
}
|
||||
return undefined;
|
||||
|
|
136
tests/baselines/reference/contextualTypeShouldBeLiteral.js
Normal file
136
tests/baselines/reference/contextualTypeShouldBeLiteral.js
Normal file
|
@ -0,0 +1,136 @@
|
|||
//// [contextualTypeShouldBeLiteral.ts]
|
||||
interface X {
|
||||
type: 'x';
|
||||
value: string;
|
||||
method(): void;
|
||||
}
|
||||
|
||||
interface Y {
|
||||
type: 'y';
|
||||
value: 'none' | 'done';
|
||||
method(): void;
|
||||
}
|
||||
|
||||
function foo(bar: X | Y) { }
|
||||
|
||||
foo({
|
||||
type: 'y',
|
||||
value: 'done',
|
||||
method() {
|
||||
this;
|
||||
this.type;
|
||||
this.value;
|
||||
}
|
||||
});
|
||||
|
||||
interface X2 {
|
||||
type1: 'x';
|
||||
value: string;
|
||||
method(): void;
|
||||
}
|
||||
|
||||
interface Y2 {
|
||||
type2: 'y';
|
||||
value: 'none' | 'done';
|
||||
method(): void;
|
||||
}
|
||||
|
||||
function foo2(bar: X2 | Y2) { }
|
||||
|
||||
foo2({
|
||||
type2: 'y',
|
||||
value: 'done',
|
||||
method() {
|
||||
this;
|
||||
this.value;
|
||||
}
|
||||
});
|
||||
|
||||
interface X3 {
|
||||
type: 'x';
|
||||
value: 1 | 2 | 3;
|
||||
xtra: number;
|
||||
}
|
||||
|
||||
interface Y3 {
|
||||
type: 'y';
|
||||
value: 11 | 12 | 13;
|
||||
ytra: number;
|
||||
}
|
||||
|
||||
let xy: X3 | Y3 = {
|
||||
type: 'y',
|
||||
value: 11,
|
||||
ytra: 12
|
||||
};
|
||||
|
||||
xy;
|
||||
|
||||
|
||||
interface LikeA {
|
||||
x: 'x';
|
||||
y: 'y';
|
||||
value: string;
|
||||
method(): void;
|
||||
}
|
||||
|
||||
interface LikeB {
|
||||
x: 'xx';
|
||||
y: 'yy';
|
||||
value: number;
|
||||
method(): void;
|
||||
}
|
||||
|
||||
let xyz: LikeA | LikeB = {
|
||||
x: 'x',
|
||||
y: 'y',
|
||||
value: "foo",
|
||||
method() {
|
||||
this;
|
||||
this.x;
|
||||
this.y;
|
||||
this.value;
|
||||
}
|
||||
};
|
||||
|
||||
xyz;
|
||||
|
||||
//// [contextualTypeShouldBeLiteral.js]
|
||||
"use strict";
|
||||
function foo(bar) { }
|
||||
foo({
|
||||
type: 'y',
|
||||
value: 'done',
|
||||
method: function () {
|
||||
this;
|
||||
this.type;
|
||||
this.value;
|
||||
}
|
||||
});
|
||||
function foo2(bar) { }
|
||||
foo2({
|
||||
type2: 'y',
|
||||
value: 'done',
|
||||
method: function () {
|
||||
this;
|
||||
this.value;
|
||||
}
|
||||
});
|
||||
var xy = {
|
||||
type: 'y',
|
||||
value: 11,
|
||||
ytra: 12
|
||||
};
|
||||
xy;
|
||||
var xyz = {
|
||||
x: 'x',
|
||||
y: 'y',
|
||||
value: "foo",
|
||||
method: function () {
|
||||
this;
|
||||
this.x;
|
||||
this.y;
|
||||
this.value;
|
||||
}
|
||||
};
|
||||
xyz;
|
229
tests/baselines/reference/contextualTypeShouldBeLiteral.symbols
Normal file
229
tests/baselines/reference/contextualTypeShouldBeLiteral.symbols
Normal file
|
@ -0,0 +1,229 @@
|
|||
=== tests/cases/compiler/contextualTypeShouldBeLiteral.ts ===
|
||||
interface X {
|
||||
>X : Symbol(X, Decl(contextualTypeShouldBeLiteral.ts, 0, 0))
|
||||
|
||||
type: 'x';
|
||||
>type : Symbol(X.type, Decl(contextualTypeShouldBeLiteral.ts, 0, 13))
|
||||
|
||||
value: string;
|
||||
>value : Symbol(X.value, Decl(contextualTypeShouldBeLiteral.ts, 1, 14))
|
||||
|
||||
method(): void;
|
||||
>method : Symbol(X.method, Decl(contextualTypeShouldBeLiteral.ts, 2, 18))
|
||||
}
|
||||
|
||||
interface Y {
|
||||
>Y : Symbol(Y, Decl(contextualTypeShouldBeLiteral.ts, 4, 1))
|
||||
|
||||
type: 'y';
|
||||
>type : Symbol(Y.type, Decl(contextualTypeShouldBeLiteral.ts, 6, 13))
|
||||
|
||||
value: 'none' | 'done';
|
||||
>value : Symbol(Y.value, Decl(contextualTypeShouldBeLiteral.ts, 7, 14))
|
||||
|
||||
method(): void;
|
||||
>method : Symbol(Y.method, Decl(contextualTypeShouldBeLiteral.ts, 8, 27))
|
||||
}
|
||||
|
||||
function foo(bar: X | Y) { }
|
||||
>foo : Symbol(foo, Decl(contextualTypeShouldBeLiteral.ts, 10, 1))
|
||||
>bar : Symbol(bar, Decl(contextualTypeShouldBeLiteral.ts, 12, 13))
|
||||
>X : Symbol(X, Decl(contextualTypeShouldBeLiteral.ts, 0, 0))
|
||||
>Y : Symbol(Y, Decl(contextualTypeShouldBeLiteral.ts, 4, 1))
|
||||
|
||||
foo({
|
||||
>foo : Symbol(foo, Decl(contextualTypeShouldBeLiteral.ts, 10, 1))
|
||||
|
||||
type: 'y',
|
||||
>type : Symbol(type, Decl(contextualTypeShouldBeLiteral.ts, 14, 5))
|
||||
|
||||
value: 'done',
|
||||
>value : Symbol(value, Decl(contextualTypeShouldBeLiteral.ts, 15, 14))
|
||||
|
||||
method() {
|
||||
>method : Symbol(method, Decl(contextualTypeShouldBeLiteral.ts, 16, 18))
|
||||
|
||||
this;
|
||||
>this : Symbol(Y, Decl(contextualTypeShouldBeLiteral.ts, 4, 1))
|
||||
|
||||
this.type;
|
||||
>this.type : Symbol(Y.type, Decl(contextualTypeShouldBeLiteral.ts, 6, 13))
|
||||
>this : Symbol(Y, Decl(contextualTypeShouldBeLiteral.ts, 4, 1))
|
||||
>type : Symbol(Y.type, Decl(contextualTypeShouldBeLiteral.ts, 6, 13))
|
||||
|
||||
this.value;
|
||||
>this.value : Symbol(Y.value, Decl(contextualTypeShouldBeLiteral.ts, 7, 14))
|
||||
>this : Symbol(Y, Decl(contextualTypeShouldBeLiteral.ts, 4, 1))
|
||||
>value : Symbol(Y.value, Decl(contextualTypeShouldBeLiteral.ts, 7, 14))
|
||||
}
|
||||
});
|
||||
|
||||
interface X2 {
|
||||
>X2 : Symbol(X2, Decl(contextualTypeShouldBeLiteral.ts, 22, 3))
|
||||
|
||||
type1: 'x';
|
||||
>type1 : Symbol(X2.type1, Decl(contextualTypeShouldBeLiteral.ts, 24, 14))
|
||||
|
||||
value: string;
|
||||
>value : Symbol(X2.value, Decl(contextualTypeShouldBeLiteral.ts, 25, 15))
|
||||
|
||||
method(): void;
|
||||
>method : Symbol(X2.method, Decl(contextualTypeShouldBeLiteral.ts, 26, 18))
|
||||
}
|
||||
|
||||
interface Y2 {
|
||||
>Y2 : Symbol(Y2, Decl(contextualTypeShouldBeLiteral.ts, 28, 1))
|
||||
|
||||
type2: 'y';
|
||||
>type2 : Symbol(Y2.type2, Decl(contextualTypeShouldBeLiteral.ts, 30, 14))
|
||||
|
||||
value: 'none' | 'done';
|
||||
>value : Symbol(Y2.value, Decl(contextualTypeShouldBeLiteral.ts, 31, 15))
|
||||
|
||||
method(): void;
|
||||
>method : Symbol(Y2.method, Decl(contextualTypeShouldBeLiteral.ts, 32, 27))
|
||||
}
|
||||
|
||||
function foo2(bar: X2 | Y2) { }
|
||||
>foo2 : Symbol(foo2, Decl(contextualTypeShouldBeLiteral.ts, 34, 1))
|
||||
>bar : Symbol(bar, Decl(contextualTypeShouldBeLiteral.ts, 36, 14))
|
||||
>X2 : Symbol(X2, Decl(contextualTypeShouldBeLiteral.ts, 22, 3))
|
||||
>Y2 : Symbol(Y2, Decl(contextualTypeShouldBeLiteral.ts, 28, 1))
|
||||
|
||||
foo2({
|
||||
>foo2 : Symbol(foo2, Decl(contextualTypeShouldBeLiteral.ts, 34, 1))
|
||||
|
||||
type2: 'y',
|
||||
>type2 : Symbol(type2, Decl(contextualTypeShouldBeLiteral.ts, 38, 6))
|
||||
|
||||
value: 'done',
|
||||
>value : Symbol(value, Decl(contextualTypeShouldBeLiteral.ts, 39, 15))
|
||||
|
||||
method() {
|
||||
>method : Symbol(method, Decl(contextualTypeShouldBeLiteral.ts, 40, 18))
|
||||
|
||||
this;
|
||||
this.value;
|
||||
>this.value : Symbol(value, Decl(contextualTypeShouldBeLiteral.ts, 25, 15), Decl(contextualTypeShouldBeLiteral.ts, 31, 15))
|
||||
>value : Symbol(value, Decl(contextualTypeShouldBeLiteral.ts, 25, 15), Decl(contextualTypeShouldBeLiteral.ts, 31, 15))
|
||||
}
|
||||
});
|
||||
|
||||
interface X3 {
|
||||
>X3 : Symbol(X3, Decl(contextualTypeShouldBeLiteral.ts, 45, 3))
|
||||
|
||||
type: 'x';
|
||||
>type : Symbol(X3.type, Decl(contextualTypeShouldBeLiteral.ts, 47, 14))
|
||||
|
||||
value: 1 | 2 | 3;
|
||||
>value : Symbol(X3.value, Decl(contextualTypeShouldBeLiteral.ts, 48, 14))
|
||||
|
||||
xtra: number;
|
||||
>xtra : Symbol(X3.xtra, Decl(contextualTypeShouldBeLiteral.ts, 49, 21))
|
||||
}
|
||||
|
||||
interface Y3 {
|
||||
>Y3 : Symbol(Y3, Decl(contextualTypeShouldBeLiteral.ts, 51, 1))
|
||||
|
||||
type: 'y';
|
||||
>type : Symbol(Y3.type, Decl(contextualTypeShouldBeLiteral.ts, 53, 14))
|
||||
|
||||
value: 11 | 12 | 13;
|
||||
>value : Symbol(Y3.value, Decl(contextualTypeShouldBeLiteral.ts, 54, 14))
|
||||
|
||||
ytra: number;
|
||||
>ytra : Symbol(Y3.ytra, Decl(contextualTypeShouldBeLiteral.ts, 55, 24))
|
||||
}
|
||||
|
||||
let xy: X3 | Y3 = {
|
||||
>xy : Symbol(xy, Decl(contextualTypeShouldBeLiteral.ts, 59, 3))
|
||||
>X3 : Symbol(X3, Decl(contextualTypeShouldBeLiteral.ts, 45, 3))
|
||||
>Y3 : Symbol(Y3, Decl(contextualTypeShouldBeLiteral.ts, 51, 1))
|
||||
|
||||
type: 'y',
|
||||
>type : Symbol(type, Decl(contextualTypeShouldBeLiteral.ts, 59, 19))
|
||||
|
||||
value: 11,
|
||||
>value : Symbol(value, Decl(contextualTypeShouldBeLiteral.ts, 60, 14))
|
||||
|
||||
ytra: 12
|
||||
>ytra : Symbol(ytra, Decl(contextualTypeShouldBeLiteral.ts, 61, 14))
|
||||
|
||||
};
|
||||
|
||||
xy;
|
||||
>xy : Symbol(xy, Decl(contextualTypeShouldBeLiteral.ts, 59, 3))
|
||||
|
||||
|
||||
interface LikeA {
|
||||
>LikeA : Symbol(LikeA, Decl(contextualTypeShouldBeLiteral.ts, 65, 3))
|
||||
|
||||
x: 'x';
|
||||
>x : Symbol(LikeA.x, Decl(contextualTypeShouldBeLiteral.ts, 68, 17))
|
||||
|
||||
y: 'y';
|
||||
>y : Symbol(LikeA.y, Decl(contextualTypeShouldBeLiteral.ts, 69, 11))
|
||||
|
||||
value: string;
|
||||
>value : Symbol(LikeA.value, Decl(contextualTypeShouldBeLiteral.ts, 70, 11))
|
||||
|
||||
method(): void;
|
||||
>method : Symbol(LikeA.method, Decl(contextualTypeShouldBeLiteral.ts, 71, 18))
|
||||
}
|
||||
|
||||
interface LikeB {
|
||||
>LikeB : Symbol(LikeB, Decl(contextualTypeShouldBeLiteral.ts, 73, 1))
|
||||
|
||||
x: 'xx';
|
||||
>x : Symbol(LikeB.x, Decl(contextualTypeShouldBeLiteral.ts, 75, 17))
|
||||
|
||||
y: 'yy';
|
||||
>y : Symbol(LikeB.y, Decl(contextualTypeShouldBeLiteral.ts, 76, 12))
|
||||
|
||||
value: number;
|
||||
>value : Symbol(LikeB.value, Decl(contextualTypeShouldBeLiteral.ts, 77, 12))
|
||||
|
||||
method(): void;
|
||||
>method : Symbol(LikeB.method, Decl(contextualTypeShouldBeLiteral.ts, 78, 18))
|
||||
}
|
||||
|
||||
let xyz: LikeA | LikeB = {
|
||||
>xyz : Symbol(xyz, Decl(contextualTypeShouldBeLiteral.ts, 82, 3))
|
||||
>LikeA : Symbol(LikeA, Decl(contextualTypeShouldBeLiteral.ts, 65, 3))
|
||||
>LikeB : Symbol(LikeB, Decl(contextualTypeShouldBeLiteral.ts, 73, 1))
|
||||
|
||||
x: 'x',
|
||||
>x : Symbol(x, Decl(contextualTypeShouldBeLiteral.ts, 82, 26))
|
||||
|
||||
y: 'y',
|
||||
>y : Symbol(y, Decl(contextualTypeShouldBeLiteral.ts, 83, 11))
|
||||
|
||||
value: "foo",
|
||||
>value : Symbol(value, Decl(contextualTypeShouldBeLiteral.ts, 84, 11))
|
||||
|
||||
method() {
|
||||
>method : Symbol(method, Decl(contextualTypeShouldBeLiteral.ts, 85, 17))
|
||||
|
||||
this;
|
||||
>this : Symbol(LikeA, Decl(contextualTypeShouldBeLiteral.ts, 65, 3))
|
||||
|
||||
this.x;
|
||||
>this.x : Symbol(LikeA.x, Decl(contextualTypeShouldBeLiteral.ts, 68, 17))
|
||||
>this : Symbol(LikeA, Decl(contextualTypeShouldBeLiteral.ts, 65, 3))
|
||||
>x : Symbol(LikeA.x, Decl(contextualTypeShouldBeLiteral.ts, 68, 17))
|
||||
|
||||
this.y;
|
||||
>this.y : Symbol(LikeA.y, Decl(contextualTypeShouldBeLiteral.ts, 69, 11))
|
||||
>this : Symbol(LikeA, Decl(contextualTypeShouldBeLiteral.ts, 65, 3))
|
||||
>y : Symbol(LikeA.y, Decl(contextualTypeShouldBeLiteral.ts, 69, 11))
|
||||
|
||||
this.value;
|
||||
>this.value : Symbol(LikeA.value, Decl(contextualTypeShouldBeLiteral.ts, 70, 11))
|
||||
>this : Symbol(LikeA, Decl(contextualTypeShouldBeLiteral.ts, 65, 3))
|
||||
>value : Symbol(LikeA.value, Decl(contextualTypeShouldBeLiteral.ts, 70, 11))
|
||||
}
|
||||
};
|
||||
|
||||
xyz;
|
||||
>xyz : Symbol(xyz, Decl(contextualTypeShouldBeLiteral.ts, 82, 3))
|
||||
|
248
tests/baselines/reference/contextualTypeShouldBeLiteral.types
Normal file
248
tests/baselines/reference/contextualTypeShouldBeLiteral.types
Normal file
|
@ -0,0 +1,248 @@
|
|||
=== tests/cases/compiler/contextualTypeShouldBeLiteral.ts ===
|
||||
interface X {
|
||||
>X : X
|
||||
|
||||
type: 'x';
|
||||
>type : "x"
|
||||
|
||||
value: string;
|
||||
>value : string
|
||||
|
||||
method(): void;
|
||||
>method : () => void
|
||||
}
|
||||
|
||||
interface Y {
|
||||
>Y : Y
|
||||
|
||||
type: 'y';
|
||||
>type : "y"
|
||||
|
||||
value: 'none' | 'done';
|
||||
>value : "none" | "done"
|
||||
|
||||
method(): void;
|
||||
>method : () => void
|
||||
}
|
||||
|
||||
function foo(bar: X | Y) { }
|
||||
>foo : (bar: X | Y) => void
|
||||
>bar : X | Y
|
||||
>X : X
|
||||
>Y : Y
|
||||
|
||||
foo({
|
||||
>foo({ type: 'y', value: 'done', method() { this; this.type; this.value; }}) : void
|
||||
>foo : (bar: X | Y) => void
|
||||
>{ type: 'y', value: 'done', method() { this; this.type; this.value; }} : { type: "y"; value: "done"; method(): void; }
|
||||
|
||||
type: 'y',
|
||||
>type : string
|
||||
>'y' : "y"
|
||||
|
||||
value: 'done',
|
||||
>value : string
|
||||
>'done' : "done"
|
||||
|
||||
method() {
|
||||
>method : () => void
|
||||
|
||||
this;
|
||||
>this : Y
|
||||
|
||||
this.type;
|
||||
>this.type : "y"
|
||||
>this : Y
|
||||
>type : "y"
|
||||
|
||||
this.value;
|
||||
>this.value : "none" | "done"
|
||||
>this : Y
|
||||
>value : "none" | "done"
|
||||
}
|
||||
});
|
||||
|
||||
interface X2 {
|
||||
>X2 : X2
|
||||
|
||||
type1: 'x';
|
||||
>type1 : "x"
|
||||
|
||||
value: string;
|
||||
>value : string
|
||||
|
||||
method(): void;
|
||||
>method : () => void
|
||||
}
|
||||
|
||||
interface Y2 {
|
||||
>Y2 : Y2
|
||||
|
||||
type2: 'y';
|
||||
>type2 : "y"
|
||||
|
||||
value: 'none' | 'done';
|
||||
>value : "none" | "done"
|
||||
|
||||
method(): void;
|
||||
>method : () => void
|
||||
}
|
||||
|
||||
function foo2(bar: X2 | Y2) { }
|
||||
>foo2 : (bar: X2 | Y2) => void
|
||||
>bar : X2 | Y2
|
||||
>X2 : X2
|
||||
>Y2 : Y2
|
||||
|
||||
foo2({
|
||||
>foo2({ type2: 'y', value: 'done', method() { this; this.value; }}) : void
|
||||
>foo2 : (bar: X2 | Y2) => void
|
||||
>{ type2: 'y', value: 'done', method() { this; this.value; }} : { type2: "y"; value: "done"; method(): void; }
|
||||
|
||||
type2: 'y',
|
||||
>type2 : string
|
||||
>'y' : "y"
|
||||
|
||||
value: 'done',
|
||||
>value : string
|
||||
>'done' : "done"
|
||||
|
||||
method() {
|
||||
>method : () => void
|
||||
|
||||
this;
|
||||
>this : X2 | Y2
|
||||
|
||||
this.value;
|
||||
>this.value : string
|
||||
>this : X2 | Y2
|
||||
>value : string
|
||||
}
|
||||
});
|
||||
|
||||
interface X3 {
|
||||
>X3 : X3
|
||||
|
||||
type: 'x';
|
||||
>type : "x"
|
||||
|
||||
value: 1 | 2 | 3;
|
||||
>value : 1 | 2 | 3
|
||||
|
||||
xtra: number;
|
||||
>xtra : number
|
||||
}
|
||||
|
||||
interface Y3 {
|
||||
>Y3 : Y3
|
||||
|
||||
type: 'y';
|
||||
>type : "y"
|
||||
|
||||
value: 11 | 12 | 13;
|
||||
>value : 11 | 12 | 13
|
||||
|
||||
ytra: number;
|
||||
>ytra : number
|
||||
}
|
||||
|
||||
let xy: X3 | Y3 = {
|
||||
>xy : X3 | Y3
|
||||
>X3 : X3
|
||||
>Y3 : Y3
|
||||
>{ type: 'y', value: 11, ytra: 12} : { type: "y"; value: 11; ytra: number; }
|
||||
|
||||
type: 'y',
|
||||
>type : string
|
||||
>'y' : "y"
|
||||
|
||||
value: 11,
|
||||
>value : number
|
||||
>11 : 11
|
||||
|
||||
ytra: 12
|
||||
>ytra : number
|
||||
>12 : 12
|
||||
|
||||
};
|
||||
|
||||
xy;
|
||||
>xy : Y3
|
||||
|
||||
|
||||
interface LikeA {
|
||||
>LikeA : LikeA
|
||||
|
||||
x: 'x';
|
||||
>x : "x"
|
||||
|
||||
y: 'y';
|
||||
>y : "y"
|
||||
|
||||
value: string;
|
||||
>value : string
|
||||
|
||||
method(): void;
|
||||
>method : () => void
|
||||
}
|
||||
|
||||
interface LikeB {
|
||||
>LikeB : LikeB
|
||||
|
||||
x: 'xx';
|
||||
>x : "xx"
|
||||
|
||||
y: 'yy';
|
||||
>y : "yy"
|
||||
|
||||
value: number;
|
||||
>value : number
|
||||
|
||||
method(): void;
|
||||
>method : () => void
|
||||
}
|
||||
|
||||
let xyz: LikeA | LikeB = {
|
||||
>xyz : LikeA | LikeB
|
||||
>LikeA : LikeA
|
||||
>LikeB : LikeB
|
||||
>{ x: 'x', y: 'y', value: "foo", method() { this; this.x; this.y; this.value; }} : { x: "x"; y: "y"; value: string; method(): void; }
|
||||
|
||||
x: 'x',
|
||||
>x : string
|
||||
>'x' : "x"
|
||||
|
||||
y: 'y',
|
||||
>y : string
|
||||
>'y' : "y"
|
||||
|
||||
value: "foo",
|
||||
>value : string
|
||||
>"foo" : "foo"
|
||||
|
||||
method() {
|
||||
>method : () => void
|
||||
|
||||
this;
|
||||
>this : LikeA
|
||||
|
||||
this.x;
|
||||
>this.x : "x"
|
||||
>this : LikeA
|
||||
>x : "x"
|
||||
|
||||
this.y;
|
||||
>this.y : "y"
|
||||
>this : LikeA
|
||||
>y : "y"
|
||||
|
||||
this.value;
|
||||
>this.value : string
|
||||
>this : LikeA
|
||||
>value : string
|
||||
}
|
||||
};
|
||||
|
||||
xyz;
|
||||
>xyz : LikeA
|
||||
|
32
tests/baselines/reference/nestedTypeVariableInfersLiteral.js
Normal file
32
tests/baselines/reference/nestedTypeVariableInfersLiteral.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
//// [nestedTypeVariableInfersLiteral.ts]
|
||||
// https://github.com/Microsoft/TypeScript/issues/19632
|
||||
declare function direct<A extends string>(a: A | A[]): Record<A, string>
|
||||
declare function nested<A extends string>(a: { fields: A }): Record<A, string>
|
||||
declare function nestedUnion<A extends string>(a: { fields: A | A[] }): Record<A, string>
|
||||
|
||||
const directUnionSingle = direct("z")
|
||||
const directUnionArray = direct(["z", "y"])
|
||||
const nestedSingle = nested({fields: "z"})
|
||||
const nestedUnionSingle = nestedUnion({fields: "z"})
|
||||
const nestedUnionArray = nestedUnion({fields: ["z", "y"]})
|
||||
|
||||
declare function hasZField(arg: { z: string }): void
|
||||
|
||||
hasZField(directUnionSingle) // ok
|
||||
hasZField(directUnionArray) // ok
|
||||
hasZField(nestedSingle) // ok
|
||||
hasZField(nestedUnionSingle) // ok
|
||||
hasZField(nestedUnionArray) // ok
|
||||
|
||||
|
||||
//// [nestedTypeVariableInfersLiteral.js]
|
||||
var directUnionSingle = direct("z");
|
||||
var directUnionArray = direct(["z", "y"]);
|
||||
var nestedSingle = nested({ fields: "z" });
|
||||
var nestedUnionSingle = nestedUnion({ fields: "z" });
|
||||
var nestedUnionArray = nestedUnion({ fields: ["z", "y"] });
|
||||
hasZField(directUnionSingle); // ok
|
||||
hasZField(directUnionArray); // ok
|
||||
hasZField(nestedSingle); // ok
|
||||
hasZField(nestedUnionSingle); // ok
|
||||
hasZField(nestedUnionArray); // ok
|
|
@ -0,0 +1,78 @@
|
|||
=== tests/cases/compiler/nestedTypeVariableInfersLiteral.ts ===
|
||||
// https://github.com/Microsoft/TypeScript/issues/19632
|
||||
declare function direct<A extends string>(a: A | A[]): Record<A, string>
|
||||
>direct : Symbol(direct, Decl(nestedTypeVariableInfersLiteral.ts, 0, 0))
|
||||
>A : Symbol(A, Decl(nestedTypeVariableInfersLiteral.ts, 1, 24))
|
||||
>a : Symbol(a, Decl(nestedTypeVariableInfersLiteral.ts, 1, 42))
|
||||
>A : Symbol(A, Decl(nestedTypeVariableInfersLiteral.ts, 1, 24))
|
||||
>A : Symbol(A, Decl(nestedTypeVariableInfersLiteral.ts, 1, 24))
|
||||
>Record : Symbol(Record, Decl(lib.d.ts, --, --))
|
||||
>A : Symbol(A, Decl(nestedTypeVariableInfersLiteral.ts, 1, 24))
|
||||
|
||||
declare function nested<A extends string>(a: { fields: A }): Record<A, string>
|
||||
>nested : Symbol(nested, Decl(nestedTypeVariableInfersLiteral.ts, 1, 72))
|
||||
>A : Symbol(A, Decl(nestedTypeVariableInfersLiteral.ts, 2, 24))
|
||||
>a : Symbol(a, Decl(nestedTypeVariableInfersLiteral.ts, 2, 42))
|
||||
>fields : Symbol(fields, Decl(nestedTypeVariableInfersLiteral.ts, 2, 46))
|
||||
>A : Symbol(A, Decl(nestedTypeVariableInfersLiteral.ts, 2, 24))
|
||||
>Record : Symbol(Record, Decl(lib.d.ts, --, --))
|
||||
>A : Symbol(A, Decl(nestedTypeVariableInfersLiteral.ts, 2, 24))
|
||||
|
||||
declare function nestedUnion<A extends string>(a: { fields: A | A[] }): Record<A, string>
|
||||
>nestedUnion : Symbol(nestedUnion, Decl(nestedTypeVariableInfersLiteral.ts, 2, 78))
|
||||
>A : Symbol(A, Decl(nestedTypeVariableInfersLiteral.ts, 3, 29))
|
||||
>a : Symbol(a, Decl(nestedTypeVariableInfersLiteral.ts, 3, 47))
|
||||
>fields : Symbol(fields, Decl(nestedTypeVariableInfersLiteral.ts, 3, 51))
|
||||
>A : Symbol(A, Decl(nestedTypeVariableInfersLiteral.ts, 3, 29))
|
||||
>A : Symbol(A, Decl(nestedTypeVariableInfersLiteral.ts, 3, 29))
|
||||
>Record : Symbol(Record, Decl(lib.d.ts, --, --))
|
||||
>A : Symbol(A, Decl(nestedTypeVariableInfersLiteral.ts, 3, 29))
|
||||
|
||||
const directUnionSingle = direct("z")
|
||||
>directUnionSingle : Symbol(directUnionSingle, Decl(nestedTypeVariableInfersLiteral.ts, 5, 5))
|
||||
>direct : Symbol(direct, Decl(nestedTypeVariableInfersLiteral.ts, 0, 0))
|
||||
|
||||
const directUnionArray = direct(["z", "y"])
|
||||
>directUnionArray : Symbol(directUnionArray, Decl(nestedTypeVariableInfersLiteral.ts, 6, 5))
|
||||
>direct : Symbol(direct, Decl(nestedTypeVariableInfersLiteral.ts, 0, 0))
|
||||
|
||||
const nestedSingle = nested({fields: "z"})
|
||||
>nestedSingle : Symbol(nestedSingle, Decl(nestedTypeVariableInfersLiteral.ts, 7, 5))
|
||||
>nested : Symbol(nested, Decl(nestedTypeVariableInfersLiteral.ts, 1, 72))
|
||||
>fields : Symbol(fields, Decl(nestedTypeVariableInfersLiteral.ts, 7, 29))
|
||||
|
||||
const nestedUnionSingle = nestedUnion({fields: "z"})
|
||||
>nestedUnionSingle : Symbol(nestedUnionSingle, Decl(nestedTypeVariableInfersLiteral.ts, 8, 5))
|
||||
>nestedUnion : Symbol(nestedUnion, Decl(nestedTypeVariableInfersLiteral.ts, 2, 78))
|
||||
>fields : Symbol(fields, Decl(nestedTypeVariableInfersLiteral.ts, 8, 39))
|
||||
|
||||
const nestedUnionArray = nestedUnion({fields: ["z", "y"]})
|
||||
>nestedUnionArray : Symbol(nestedUnionArray, Decl(nestedTypeVariableInfersLiteral.ts, 9, 5))
|
||||
>nestedUnion : Symbol(nestedUnion, Decl(nestedTypeVariableInfersLiteral.ts, 2, 78))
|
||||
>fields : Symbol(fields, Decl(nestedTypeVariableInfersLiteral.ts, 9, 38))
|
||||
|
||||
declare function hasZField(arg: { z: string }): void
|
||||
>hasZField : Symbol(hasZField, Decl(nestedTypeVariableInfersLiteral.ts, 9, 58))
|
||||
>arg : Symbol(arg, Decl(nestedTypeVariableInfersLiteral.ts, 11, 27))
|
||||
>z : Symbol(z, Decl(nestedTypeVariableInfersLiteral.ts, 11, 33))
|
||||
|
||||
hasZField(directUnionSingle) // ok
|
||||
>hasZField : Symbol(hasZField, Decl(nestedTypeVariableInfersLiteral.ts, 9, 58))
|
||||
>directUnionSingle : Symbol(directUnionSingle, Decl(nestedTypeVariableInfersLiteral.ts, 5, 5))
|
||||
|
||||
hasZField(directUnionArray) // ok
|
||||
>hasZField : Symbol(hasZField, Decl(nestedTypeVariableInfersLiteral.ts, 9, 58))
|
||||
>directUnionArray : Symbol(directUnionArray, Decl(nestedTypeVariableInfersLiteral.ts, 6, 5))
|
||||
|
||||
hasZField(nestedSingle) // ok
|
||||
>hasZField : Symbol(hasZField, Decl(nestedTypeVariableInfersLiteral.ts, 9, 58))
|
||||
>nestedSingle : Symbol(nestedSingle, Decl(nestedTypeVariableInfersLiteral.ts, 7, 5))
|
||||
|
||||
hasZField(nestedUnionSingle) // ok
|
||||
>hasZField : Symbol(hasZField, Decl(nestedTypeVariableInfersLiteral.ts, 9, 58))
|
||||
>nestedUnionSingle : Symbol(nestedUnionSingle, Decl(nestedTypeVariableInfersLiteral.ts, 8, 5))
|
||||
|
||||
hasZField(nestedUnionArray) // ok
|
||||
>hasZField : Symbol(hasZField, Decl(nestedTypeVariableInfersLiteral.ts, 9, 58))
|
||||
>nestedUnionArray : Symbol(nestedUnionArray, Decl(nestedTypeVariableInfersLiteral.ts, 9, 5))
|
||||
|
100
tests/baselines/reference/nestedTypeVariableInfersLiteral.types
Normal file
100
tests/baselines/reference/nestedTypeVariableInfersLiteral.types
Normal file
|
@ -0,0 +1,100 @@
|
|||
=== tests/cases/compiler/nestedTypeVariableInfersLiteral.ts ===
|
||||
// https://github.com/Microsoft/TypeScript/issues/19632
|
||||
declare function direct<A extends string>(a: A | A[]): Record<A, string>
|
||||
>direct : <A extends string>(a: A | A[]) => Record<A, string>
|
||||
>A : A
|
||||
>a : A | A[]
|
||||
>A : A
|
||||
>A : A
|
||||
>Record : Record<K, T>
|
||||
>A : A
|
||||
|
||||
declare function nested<A extends string>(a: { fields: A }): Record<A, string>
|
||||
>nested : <A extends string>(a: { fields: A; }) => Record<A, string>
|
||||
>A : A
|
||||
>a : { fields: A; }
|
||||
>fields : A
|
||||
>A : A
|
||||
>Record : Record<K, T>
|
||||
>A : A
|
||||
|
||||
declare function nestedUnion<A extends string>(a: { fields: A | A[] }): Record<A, string>
|
||||
>nestedUnion : <A extends string>(a: { fields: A | A[]; }) => Record<A, string>
|
||||
>A : A
|
||||
>a : { fields: A | A[]; }
|
||||
>fields : A | A[]
|
||||
>A : A
|
||||
>A : A
|
||||
>Record : Record<K, T>
|
||||
>A : A
|
||||
|
||||
const directUnionSingle = direct("z")
|
||||
>directUnionSingle : Record<"z", string>
|
||||
>direct("z") : Record<"z", string>
|
||||
>direct : <A extends string>(a: A | A[]) => Record<A, string>
|
||||
>"z" : "z"
|
||||
|
||||
const directUnionArray = direct(["z", "y"])
|
||||
>directUnionArray : Record<"z" | "y", string>
|
||||
>direct(["z", "y"]) : Record<"z" | "y", string>
|
||||
>direct : <A extends string>(a: A | A[]) => Record<A, string>
|
||||
>["z", "y"] : ("z" | "y")[]
|
||||
>"z" : "z"
|
||||
>"y" : "y"
|
||||
|
||||
const nestedSingle = nested({fields: "z"})
|
||||
>nestedSingle : Record<"z", string>
|
||||
>nested({fields: "z"}) : Record<"z", string>
|
||||
>nested : <A extends string>(a: { fields: A; }) => Record<A, string>
|
||||
>{fields: "z"} : { fields: "z"; }
|
||||
>fields : string
|
||||
>"z" : "z"
|
||||
|
||||
const nestedUnionSingle = nestedUnion({fields: "z"})
|
||||
>nestedUnionSingle : Record<"z", string>
|
||||
>nestedUnion({fields: "z"}) : Record<"z", string>
|
||||
>nestedUnion : <A extends string>(a: { fields: A | A[]; }) => Record<A, string>
|
||||
>{fields: "z"} : { fields: "z"; }
|
||||
>fields : string
|
||||
>"z" : "z"
|
||||
|
||||
const nestedUnionArray = nestedUnion({fields: ["z", "y"]})
|
||||
>nestedUnionArray : Record<"z" | "y", string>
|
||||
>nestedUnion({fields: ["z", "y"]}) : Record<"z" | "y", string>
|
||||
>nestedUnion : <A extends string>(a: { fields: A | A[]; }) => Record<A, string>
|
||||
>{fields: ["z", "y"]} : { fields: ("z" | "y")[]; }
|
||||
>fields : ("z" | "y")[]
|
||||
>["z", "y"] : ("z" | "y")[]
|
||||
>"z" : "z"
|
||||
>"y" : "y"
|
||||
|
||||
declare function hasZField(arg: { z: string }): void
|
||||
>hasZField : (arg: { z: string; }) => void
|
||||
>arg : { z: string; }
|
||||
>z : string
|
||||
|
||||
hasZField(directUnionSingle) // ok
|
||||
>hasZField(directUnionSingle) : void
|
||||
>hasZField : (arg: { z: string; }) => void
|
||||
>directUnionSingle : Record<"z", string>
|
||||
|
||||
hasZField(directUnionArray) // ok
|
||||
>hasZField(directUnionArray) : void
|
||||
>hasZField : (arg: { z: string; }) => void
|
||||
>directUnionArray : Record<"z" | "y", string>
|
||||
|
||||
hasZField(nestedSingle) // ok
|
||||
>hasZField(nestedSingle) : void
|
||||
>hasZField : (arg: { z: string; }) => void
|
||||
>nestedSingle : Record<"z", string>
|
||||
|
||||
hasZField(nestedUnionSingle) // ok
|
||||
>hasZField(nestedUnionSingle) : void
|
||||
>hasZField : (arg: { z: string; }) => void
|
||||
>nestedUnionSingle : Record<"z", string>
|
||||
|
||||
hasZField(nestedUnionArray) // ok
|
||||
>hasZField(nestedUnionArray) : void
|
||||
>hasZField : (arg: { z: string; }) => void
|
||||
>nestedUnionArray : Record<"z" | "y", string>
|
||||
|
96
tests/cases/compiler/contextualTypeShouldBeLiteral.ts
Normal file
96
tests/cases/compiler/contextualTypeShouldBeLiteral.ts
Normal file
|
@ -0,0 +1,96 @@
|
|||
// @strict: true
|
||||
interface X {
|
||||
type: 'x';
|
||||
value: string;
|
||||
method(): void;
|
||||
}
|
||||
|
||||
interface Y {
|
||||
type: 'y';
|
||||
value: 'none' | 'done';
|
||||
method(): void;
|
||||
}
|
||||
|
||||
function foo(bar: X | Y) { }
|
||||
|
||||
foo({
|
||||
type: 'y',
|
||||
value: 'done',
|
||||
method() {
|
||||
this;
|
||||
this.type;
|
||||
this.value;
|
||||
}
|
||||
});
|
||||
|
||||
interface X2 {
|
||||
type1: 'x';
|
||||
value: string;
|
||||
method(): void;
|
||||
}
|
||||
|
||||
interface Y2 {
|
||||
type2: 'y';
|
||||
value: 'none' | 'done';
|
||||
method(): void;
|
||||
}
|
||||
|
||||
function foo2(bar: X2 | Y2) { }
|
||||
|
||||
foo2({
|
||||
type2: 'y',
|
||||
value: 'done',
|
||||
method() {
|
||||
this;
|
||||
this.value;
|
||||
}
|
||||
});
|
||||
|
||||
interface X3 {
|
||||
type: 'x';
|
||||
value: 1 | 2 | 3;
|
||||
xtra: number;
|
||||
}
|
||||
|
||||
interface Y3 {
|
||||
type: 'y';
|
||||
value: 11 | 12 | 13;
|
||||
ytra: number;
|
||||
}
|
||||
|
||||
let xy: X3 | Y3 = {
|
||||
type: 'y',
|
||||
value: 11,
|
||||
ytra: 12
|
||||
};
|
||||
|
||||
xy;
|
||||
|
||||
|
||||
interface LikeA {
|
||||
x: 'x';
|
||||
y: 'y';
|
||||
value: string;
|
||||
method(): void;
|
||||
}
|
||||
|
||||
interface LikeB {
|
||||
x: 'xx';
|
||||
y: 'yy';
|
||||
value: number;
|
||||
method(): void;
|
||||
}
|
||||
|
||||
let xyz: LikeA | LikeB = {
|
||||
x: 'x',
|
||||
y: 'y',
|
||||
value: "foo",
|
||||
method() {
|
||||
this;
|
||||
this.x;
|
||||
this.y;
|
||||
this.value;
|
||||
}
|
||||
};
|
||||
|
||||
xyz;
|
18
tests/cases/compiler/nestedTypeVariableInfersLiteral.ts
Normal file
18
tests/cases/compiler/nestedTypeVariableInfersLiteral.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
// https://github.com/Microsoft/TypeScript/issues/19632
|
||||
declare function direct<A extends string>(a: A | A[]): Record<A, string>
|
||||
declare function nested<A extends string>(a: { fields: A }): Record<A, string>
|
||||
declare function nestedUnion<A extends string>(a: { fields: A | A[] }): Record<A, string>
|
||||
|
||||
const directUnionSingle = direct("z")
|
||||
const directUnionArray = direct(["z", "y"])
|
||||
const nestedSingle = nested({fields: "z"})
|
||||
const nestedUnionSingle = nestedUnion({fields: "z"})
|
||||
const nestedUnionArray = nestedUnion({fields: ["z", "y"]})
|
||||
|
||||
declare function hasZField(arg: { z: string }): void
|
||||
|
||||
hasZField(directUnionSingle) // ok
|
||||
hasZField(directUnionArray) // ok
|
||||
hasZField(nestedSingle) // ok
|
||||
hasZField(nestedUnionSingle) // ok
|
||||
hasZField(nestedUnionArray) // ok
|
|
@ -1 +1 @@
|
|||
Subproject commit ed149eb0c787b1195a95b44105822c64bb6eb636
|
||||
Subproject commit 9c8f67f596e23283f7fe452d67372233d2e4e5d6
|
10004
tests/cases/user/literal-no-oom/index.ts
Normal file
10004
tests/cases/user/literal-no-oom/index.ts
Normal file
File diff suppressed because it is too large
Load diff
6
tests/cases/user/literal-no-oom/tsconfig.json
Normal file
6
tests/cases/user/literal-no-oom/tsconfig.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"types": []
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue