mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-09 12:15:34 -06:00
Preserve generics in contextual types for rest arguments (#44122)
* Move all getIndexedAccessType flags to AccessFlags enum * Preserve generics in contextual types for rest arguments * Add regression test
This commit is contained in:
parent
73736d9b84
commit
e67da8a748
@ -180,15 +180,6 @@ namespace ts {
|
||||
IsForSignatureHelp = 1 << 4, // Call resolution for purposes of signature help
|
||||
}
|
||||
|
||||
const enum AccessFlags {
|
||||
None = 0,
|
||||
NoIndexSignatures = 1 << 0,
|
||||
Writing = 1 << 1,
|
||||
CacheSymbol = 1 << 2,
|
||||
NoTupleBoundsCheck = 1 << 3,
|
||||
ExpressionPosition = 1 << 4,
|
||||
}
|
||||
|
||||
const enum SignatureCheckMode {
|
||||
BivariantCallback = 1 << 0,
|
||||
StrictCallback = 1 << 1,
|
||||
@ -8317,7 +8308,7 @@ namespace ts {
|
||||
// Use explicitly specified property name ({ p: xxx } form), or otherwise the implied name ({ p } form)
|
||||
const name = declaration.propertyName || declaration.name as Identifier;
|
||||
const indexType = getLiteralTypeFromPropertyName(name);
|
||||
const declaredType = getIndexedAccessType(parentType, indexType, /*noUncheckedIndexedAccessCandidate*/ undefined, name, /*aliasSymbol*/ undefined, /*aliasTypeArguments*/ undefined, AccessFlags.ExpressionPosition);
|
||||
const declaredType = getIndexedAccessType(parentType, indexType, AccessFlags.ExpressionPosition, name);
|
||||
type = getFlowTypeOfDestructuring(declaration, declaredType);
|
||||
}
|
||||
}
|
||||
@ -8337,8 +8328,8 @@ namespace ts {
|
||||
}
|
||||
else if (isArrayLikeType(parentType)) {
|
||||
const indexType = getLiteralType(index);
|
||||
const accessFlags = hasDefaultValue(declaration) ? AccessFlags.NoTupleBoundsCheck : 0;
|
||||
const declaredType = getIndexedAccessTypeOrUndefined(parentType, indexType, /*noUncheckedIndexedAccessCandidate*/ undefined, declaration.name, accessFlags | AccessFlags.ExpressionPosition) || errorType;
|
||||
const accessFlags = AccessFlags.ExpressionPosition | (hasDefaultValue(declaration) ? AccessFlags.NoTupleBoundsCheck : 0);
|
||||
const declaredType = getIndexedAccessTypeOrUndefined(parentType, indexType, accessFlags, declaration.name) || errorType;
|
||||
type = getFlowTypeOfDestructuring(declaration, declaredType);
|
||||
}
|
||||
else {
|
||||
@ -11400,14 +11391,14 @@ namespace ts {
|
||||
function getConstraintFromIndexedAccess(type: IndexedAccessType) {
|
||||
const indexConstraint = getSimplifiedTypeOrConstraint(type.indexType);
|
||||
if (indexConstraint && indexConstraint !== type.indexType) {
|
||||
const indexedAccess = getIndexedAccessTypeOrUndefined(type.objectType, indexConstraint, type.noUncheckedIndexedAccessCandidate);
|
||||
const indexedAccess = getIndexedAccessTypeOrUndefined(type.objectType, indexConstraint, type.accessFlags);
|
||||
if (indexedAccess) {
|
||||
return indexedAccess;
|
||||
}
|
||||
}
|
||||
const objectConstraint = getSimplifiedTypeOrConstraint(type.objectType);
|
||||
if (objectConstraint && objectConstraint !== type.objectType) {
|
||||
return getIndexedAccessTypeOrUndefined(objectConstraint, type.indexType, type.noUncheckedIndexedAccessCandidate);
|
||||
return getIndexedAccessTypeOrUndefined(objectConstraint, type.indexType, type.accessFlags);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
@ -11613,7 +11604,7 @@ namespace ts {
|
||||
if (t.flags & TypeFlags.IndexedAccess) {
|
||||
const baseObjectType = getBaseConstraint((t as IndexedAccessType).objectType);
|
||||
const baseIndexType = getBaseConstraint((t as IndexedAccessType).indexType);
|
||||
const baseIndexedAccess = baseObjectType && baseIndexType && getIndexedAccessTypeOrUndefined(baseObjectType, baseIndexType, (t as IndexedAccessType).noUncheckedIndexedAccessCandidate);
|
||||
const baseIndexedAccess = baseObjectType && baseIndexType && getIndexedAccessTypeOrUndefined(baseObjectType, baseIndexType, (t as IndexedAccessType).accessFlags);
|
||||
return baseIndexedAccess && getBaseConstraint(baseIndexedAccess);
|
||||
}
|
||||
if (t.flags & TypeFlags.Conditional) {
|
||||
@ -14560,13 +14551,13 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
function createIndexedAccessType(objectType: Type, indexType: Type, aliasSymbol: Symbol | undefined, aliasTypeArguments: readonly Type[] | undefined, shouldIncludeUndefined: boolean) {
|
||||
function createIndexedAccessType(objectType: Type, indexType: Type, accessFlags: AccessFlags, aliasSymbol: Symbol | undefined, aliasTypeArguments: readonly Type[] | undefined) {
|
||||
const type = createType(TypeFlags.IndexedAccess) as IndexedAccessType;
|
||||
type.objectType = objectType;
|
||||
type.indexType = indexType;
|
||||
type.accessFlags = accessFlags;
|
||||
type.aliasSymbol = aliasSymbol;
|
||||
type.aliasTypeArguments = aliasTypeArguments;
|
||||
type.noUncheckedIndexedAccessCandidate = shouldIncludeUndefined;
|
||||
return type;
|
||||
}
|
||||
|
||||
@ -14619,14 +14610,17 @@ namespace ts {
|
||||
return true;
|
||||
}
|
||||
|
||||
function getPropertyTypeForIndexType(originalObjectType: Type, objectType: Type, indexType: Type, fullIndexType: Type, suppressNoImplicitAnyError: boolean, accessNode: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression | undefined, accessFlags: AccessFlags, noUncheckedIndexedAccessCandidate?: boolean, reportDeprecated?: boolean) {
|
||||
function getPropertyTypeForIndexType(originalObjectType: Type, objectType: Type, indexType: Type, fullIndexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression | undefined, accessFlags: AccessFlags) {
|
||||
const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode : undefined;
|
||||
const propName = accessNode && isPrivateIdentifier(accessNode) ? undefined : getPropertyNameFromIndex(indexType, accessNode);
|
||||
|
||||
if (propName !== undefined) {
|
||||
if (accessFlags & AccessFlags.Contextual) {
|
||||
return getTypeOfPropertyOfContextualType(objectType, propName) || anyType;
|
||||
}
|
||||
const prop = getPropertyOfType(objectType, propName);
|
||||
if (prop) {
|
||||
if (reportDeprecated && accessNode && prop.declarations && getDeclarationNodeFlagsFromSymbol(prop) & NodeFlags.Deprecated && isUncalledFunctionReference(accessNode, prop)) {
|
||||
if (accessFlags & AccessFlags.ReportDeprecated && accessNode && prop.declarations && getDeclarationNodeFlagsFromSymbol(prop) & NodeFlags.Deprecated && isUncalledFunctionReference(accessNode, prop)) {
|
||||
const deprecatedNode = accessExpression?.argumentExpression ?? (isIndexedAccessTypeNode(accessNode) ? accessNode.indexType : accessNode);
|
||||
addDeprecatedSuggestion(deprecatedNode, prop.declarations, propName as string);
|
||||
}
|
||||
@ -14662,7 +14656,7 @@ namespace ts {
|
||||
errorIfWritingToReadonlyIndex(getIndexInfoOfType(objectType, IndexKind.Number));
|
||||
return mapType(objectType, t => {
|
||||
const restType = getRestTypeOfTupleType(t as TupleTypeReference) || undefinedType;
|
||||
return noUncheckedIndexedAccessCandidate ? getUnionType([restType, undefinedType]) : restType;
|
||||
return accessFlags & AccessFlags.IncludeUndefined ? getUnionType([restType, undefinedType]) : restType;
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -14682,10 +14676,10 @@ namespace ts {
|
||||
if (accessNode && !isTypeAssignableToKind(indexType, TypeFlags.String | TypeFlags.Number)) {
|
||||
const indexNode = getIndexNodeForAccessExpression(accessNode);
|
||||
error(indexNode, Diagnostics.Type_0_cannot_be_used_as_an_index_type, typeToString(indexType));
|
||||
return noUncheckedIndexedAccessCandidate ? getUnionType([indexInfo.type, undefinedType]) : indexInfo.type;
|
||||
return accessFlags & AccessFlags.IncludeUndefined ? getUnionType([indexInfo.type, undefinedType]) : indexInfo.type;
|
||||
}
|
||||
errorIfWritingToReadonlyIndex(indexInfo);
|
||||
return noUncheckedIndexedAccessCandidate ? getUnionType([indexInfo.type, undefinedType]) : indexInfo.type;
|
||||
return accessFlags & AccessFlags.IncludeUndefined ? getUnionType([indexInfo.type, undefinedType]) : indexInfo.type;
|
||||
}
|
||||
if (indexType.flags & TypeFlags.Never) {
|
||||
return neverType;
|
||||
@ -14710,7 +14704,7 @@ namespace ts {
|
||||
if (objectType.symbol === globalThisSymbol && propName !== undefined && globalThisSymbol.exports!.has(propName) && (globalThisSymbol.exports!.get(propName)!.flags & SymbolFlags.BlockScoped)) {
|
||||
error(accessExpression, Diagnostics.Property_0_does_not_exist_on_type_1, unescapeLeadingUnderscores(propName), typeToString(objectType));
|
||||
}
|
||||
else if (noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors && !suppressNoImplicitAnyError) {
|
||||
else if (noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors && !(accessFlags & AccessFlags.SuppressNoImplicitAnyError)) {
|
||||
if (propName !== undefined && typeHasStaticProperty(propName, objectType)) {
|
||||
const typeName = typeToString(objectType);
|
||||
error(accessExpression, Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_to_access_the_static_member_2_instead, propName as string, typeName, typeName + "[" + getTextOfNode(accessExpression.argumentExpression) + "]");
|
||||
@ -14963,8 +14957,8 @@ namespace ts {
|
||||
return instantiateType(getTemplateTypeFromMappedType(objectType), templateMapper);
|
||||
}
|
||||
|
||||
function getIndexedAccessType(objectType: Type, indexType: Type, noUncheckedIndexedAccessCandidate?: boolean, accessNode?: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[], accessFlags = AccessFlags.None): Type {
|
||||
return getIndexedAccessTypeOrUndefined(objectType, indexType, noUncheckedIndexedAccessCandidate, accessNode, accessFlags, aliasSymbol, aliasTypeArguments) || (accessNode ? errorType : unknownType);
|
||||
function getIndexedAccessType(objectType: Type, indexType: Type, accessFlags = AccessFlags.None, accessNode?: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type {
|
||||
return getIndexedAccessTypeOrUndefined(objectType, indexType, accessFlags, accessNode, aliasSymbol, aliasTypeArguments) || (accessNode ? errorType : unknownType);
|
||||
}
|
||||
|
||||
function indexTypeLessThan(indexType: Type, limit: number) {
|
||||
@ -14980,20 +14974,18 @@ namespace ts {
|
||||
});
|
||||
}
|
||||
|
||||
function getIndexedAccessTypeOrUndefined(objectType: Type, indexType: Type, noUncheckedIndexedAccessCandidate?: boolean, accessNode?: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression, accessFlags = AccessFlags.None, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type | undefined {
|
||||
function getIndexedAccessTypeOrUndefined(objectType: Type, indexType: Type, accessFlags = AccessFlags.None, accessNode?: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | BindingName | SyntheticExpression, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type | undefined {
|
||||
if (objectType === wildcardType || indexType === wildcardType) {
|
||||
return wildcardType;
|
||||
}
|
||||
|
||||
const shouldIncludeUndefined = noUncheckedIndexedAccessCandidate ||
|
||||
(!!compilerOptions.noUncheckedIndexedAccess &&
|
||||
(accessFlags & (AccessFlags.Writing | AccessFlags.ExpressionPosition)) === AccessFlags.ExpressionPosition);
|
||||
|
||||
// If the object type has a string index signature and no other members we know that the result will
|
||||
// always be the type of that index signature and we can simplify accordingly.
|
||||
if (isStringIndexSignatureOnlyType(objectType) && !(indexType.flags & TypeFlags.Nullable) && isTypeAssignableToKind(indexType, TypeFlags.String | TypeFlags.Number)) {
|
||||
indexType = stringType;
|
||||
}
|
||||
// In noUncheckedIndexedAccess mode, indexed access operations that occur in an expression in a read position and resolve to
|
||||
// an index signature have 'undefined' included in their type.
|
||||
if (compilerOptions.noUncheckedIndexedAccess && accessFlags & AccessFlags.ExpressionPosition) accessFlags |= AccessFlags.IncludeUndefined;
|
||||
// If the index type is generic, or if the object type is generic and doesn't originate in an expression and
|
||||
// the operation isn't exclusively indexing the fixed (non-variadic) portion of a tuple type, we are performing
|
||||
// a higher-order index access where we cannot meaningfully access the properties of the object type. Note that
|
||||
@ -15007,10 +14999,11 @@ namespace ts {
|
||||
return objectType;
|
||||
}
|
||||
// Defer the operation by creating an indexed access type.
|
||||
const id = objectType.id + "," + indexType.id + (shouldIncludeUndefined ? "?" : "") + getAliasId(aliasSymbol, aliasTypeArguments);
|
||||
const persistentAccessFlags = accessFlags & AccessFlags.Persistent;
|
||||
const id = objectType.id + "," + indexType.id + "," + persistentAccessFlags + getAliasId(aliasSymbol, aliasTypeArguments);
|
||||
let type = indexedAccessTypes.get(id);
|
||||
if (!type) {
|
||||
indexedAccessTypes.set(id, type = createIndexedAccessType(objectType, indexType, aliasSymbol, aliasTypeArguments, shouldIncludeUndefined));
|
||||
indexedAccessTypes.set(id, type = createIndexedAccessType(objectType, indexType, persistentAccessFlags, aliasSymbol, aliasTypeArguments));
|
||||
}
|
||||
|
||||
return type;
|
||||
@ -15023,7 +15016,7 @@ namespace ts {
|
||||
const propTypes: Type[] = [];
|
||||
let wasMissingProp = false;
|
||||
for (const t of (indexType as UnionType).types) {
|
||||
const propType = getPropertyTypeForIndexType(objectType, apparentObjectType, t, indexType, wasMissingProp, accessNode, accessFlags, shouldIncludeUndefined);
|
||||
const propType = getPropertyTypeForIndexType(objectType, apparentObjectType, t, indexType, accessNode, accessFlags | (wasMissingProp ? AccessFlags.SuppressNoImplicitAnyError : 0));
|
||||
if (propType) {
|
||||
propTypes.push(propType);
|
||||
}
|
||||
@ -15043,7 +15036,7 @@ namespace ts {
|
||||
? getIntersectionType(propTypes, aliasSymbol, aliasTypeArguments)
|
||||
: getUnionType(propTypes, UnionReduction.Literal, aliasSymbol, aliasTypeArguments);
|
||||
}
|
||||
return getPropertyTypeForIndexType(objectType, apparentObjectType, indexType, indexType, /* supressNoImplicitAnyError */ false, accessNode, accessFlags | AccessFlags.CacheSymbol, shouldIncludeUndefined, /* reportDeprecated */ true);
|
||||
return getPropertyTypeForIndexType(objectType, apparentObjectType, indexType, indexType, accessNode, accessFlags | AccessFlags.CacheSymbol | AccessFlags.ReportDeprecated);
|
||||
}
|
||||
|
||||
function getTypeFromIndexedAccessTypeNode(node: IndexedAccessTypeNode) {
|
||||
@ -15052,7 +15045,7 @@ namespace ts {
|
||||
const objectType = getTypeFromTypeNode(node.objectType);
|
||||
const indexType = getTypeFromTypeNode(node.indexType);
|
||||
const potentialAlias = getAliasSymbolForTypeNode(node);
|
||||
const resolved = getIndexedAccessType(objectType, indexType, /*noUncheckedIndexedAccessCandidate*/ undefined, node, potentialAlias, getTypeArgumentsForAliasSymbol(potentialAlias));
|
||||
const resolved = getIndexedAccessType(objectType, indexType, AccessFlags.None, node, potentialAlias, getTypeArgumentsForAliasSymbol(potentialAlias));
|
||||
links.resolvedType = resolved.flags & TypeFlags.IndexedAccess &&
|
||||
(resolved as IndexedAccessType).objectType === objectType &&
|
||||
(resolved as IndexedAccessType).indexType === indexType ?
|
||||
@ -16281,7 +16274,7 @@ namespace ts {
|
||||
if (flags & TypeFlags.IndexedAccess) {
|
||||
const newAliasSymbol = aliasSymbol || type.aliasSymbol;
|
||||
const newAliasTypeArguments = aliasSymbol ? aliasTypeArguments : instantiateTypes(type.aliasTypeArguments, mapper);
|
||||
return getIndexedAccessType(instantiateType((type as IndexedAccessType).objectType, mapper), instantiateType((type as IndexedAccessType).indexType, mapper), (type as IndexedAccessType).noUncheckedIndexedAccessCandidate, /*accessNode*/ undefined, newAliasSymbol, newAliasTypeArguments);
|
||||
return getIndexedAccessType(instantiateType((type as IndexedAccessType).objectType, mapper), instantiateType((type as IndexedAccessType).indexType, mapper), (type as IndexedAccessType).accessFlags, /*accessNode*/ undefined, newAliasSymbol, newAliasTypeArguments);
|
||||
}
|
||||
if (flags & TypeFlags.Conditional) {
|
||||
return getConditionalTypeInstantiation(type as ConditionalType, combineTypeMappers((type as ConditionalType).mapper, mapper), aliasSymbol, aliasTypeArguments);
|
||||
@ -18472,7 +18465,7 @@ namespace ts {
|
||||
const baseIndexType = getBaseConstraintOfType(indexType) || indexType;
|
||||
if (!isGenericObjectType(baseObjectType) && !isGenericIndexType(baseIndexType)) {
|
||||
const accessFlags = AccessFlags.Writing | (baseObjectType !== objectType ? AccessFlags.NoIndexSignatures : 0);
|
||||
const constraint = getIndexedAccessTypeOrUndefined(baseObjectType, baseIndexType, (target as IndexedAccessType).noUncheckedIndexedAccessCandidate, /*accessNode*/ undefined, accessFlags);
|
||||
const constraint = getIndexedAccessTypeOrUndefined(baseObjectType, baseIndexType, accessFlags);
|
||||
if (constraint) {
|
||||
if (reportErrors && originalErrorInfo) {
|
||||
// create a new chain for the constraint error
|
||||
@ -25192,7 +25185,10 @@ namespace ts {
|
||||
if (isJsxOpeningLikeElement(callTarget) && argIndex === 0) {
|
||||
return getEffectiveFirstArgumentForJsxSignature(signature, callTarget);
|
||||
}
|
||||
return getTypeAtPosition(signature, argIndex);
|
||||
const restIndex = signature.parameters.length - 1;
|
||||
return signatureHasRestParameter(signature) && argIndex >= restIndex ?
|
||||
getIndexedAccessType(getTypeOfSymbol(signature.parameters[restIndex]), getLiteralType(argIndex - restIndex), AccessFlags.Contextual) :
|
||||
getTypeAtPosition(signature, argIndex);
|
||||
}
|
||||
|
||||
function getContextualTypeForSubstitutionExpression(template: TemplateExpression, substitutionExpression: Expression) {
|
||||
@ -27949,8 +27945,8 @@ namespace ts {
|
||||
const effectiveIndexType = isForInVariableForNumericPropertyNames(indexExpression) ? numberType : indexType;
|
||||
const accessFlags = isAssignmentTarget(node) ?
|
||||
AccessFlags.Writing | (isGenericObjectType(objectType) && !isThisTypeParameter(objectType) ? AccessFlags.NoIndexSignatures : 0) :
|
||||
AccessFlags.None;
|
||||
const indexedAccessType = getIndexedAccessTypeOrUndefined(objectType, effectiveIndexType, /*noUncheckedIndexedAccessCandidate*/ undefined, node, accessFlags | AccessFlags.ExpressionPosition) || errorType;
|
||||
AccessFlags.ExpressionPosition;
|
||||
const indexedAccessType = getIndexedAccessTypeOrUndefined(objectType, effectiveIndexType, accessFlags, node) || errorType;
|
||||
return checkIndexedAccessIndexType(getFlowTypeOfAccessExpression(node, getNodeLinks(node).resolvedSymbol, indexedAccessType, indexExpression, checkMode), node);
|
||||
}
|
||||
|
||||
@ -28307,7 +28303,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
else {
|
||||
const contextualType = getIndexedAccessType(restType, getLiteralType(i - index));
|
||||
const contextualType = getIndexedAccessType(restType, getLiteralType(i - index), AccessFlags.Contextual);
|
||||
const argType = checkExpressionWithContextualType(arg, contextualType, context, checkMode);
|
||||
const hasPrimitiveContextualType = maybeTypeOfKind(contextualType, TypeFlags.Primitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping);
|
||||
types.push(hasPrimitiveContextualType ? getRegularTypeOfLiteralType(argType) : getWidenedLiteralType(argType));
|
||||
@ -31493,7 +31489,7 @@ namespace ts {
|
||||
checkPropertyAccessibility(property, /*isSuper*/ false, /*writing*/ true, objectLiteralType, prop);
|
||||
}
|
||||
}
|
||||
const elementType = getIndexedAccessType(objectLiteralType, exprType, /*noUncheckedIndexedAccessCandidate*/ undefined, name, /*aliasSymbol*/ undefined, /*aliasTypeArguments*/ undefined, AccessFlags.ExpressionPosition);
|
||||
const elementType = getIndexedAccessType(objectLiteralType, exprType, AccessFlags.ExpressionPosition, name);
|
||||
const type = getFlowTypeOfDestructuring(property, elementType);
|
||||
return checkDestructuringAssignment(property.kind === SyntaxKind.ShorthandPropertyAssignment ? property : property.initializer, type);
|
||||
}
|
||||
@ -31554,7 +31550,7 @@ namespace ts {
|
||||
// We create a synthetic expression so that getIndexedAccessType doesn't get confused
|
||||
// when the element is a SyntaxKind.ElementAccessExpression.
|
||||
const accessFlags = AccessFlags.ExpressionPosition | (hasDefaultValue(element) ? AccessFlags.NoTupleBoundsCheck : 0);
|
||||
const elementType = getIndexedAccessTypeOrUndefined(sourceType, indexType, /*noUncheckedIndexedAccessCandidate*/ undefined, createSyntheticExpression(element, indexType), accessFlags) || errorType;
|
||||
const elementType = getIndexedAccessTypeOrUndefined(sourceType, indexType, accessFlags, createSyntheticExpression(element, indexType)) || errorType;
|
||||
const assignedType = hasDefaultValue(element) ? getTypeWithFacts(elementType, TypeFacts.NEUndefined) : elementType;
|
||||
const type = getFlowTypeOfDestructuring(element, assignedType);
|
||||
return checkDestructuringAssignment(element, type, checkMode);
|
||||
|
||||
@ -5491,17 +5491,28 @@ namespace ts {
|
||||
resolvedDefaultType?: Type;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export const enum AccessFlags {
|
||||
None = 0,
|
||||
IncludeUndefined = 1 << 0,
|
||||
NoIndexSignatures = 1 << 1,
|
||||
Writing = 1 << 2,
|
||||
CacheSymbol = 1 << 3,
|
||||
NoTupleBoundsCheck = 1 << 4,
|
||||
ExpressionPosition = 1 << 5,
|
||||
ReportDeprecated = 1 << 6,
|
||||
SuppressNoImplicitAnyError = 1 << 7,
|
||||
Contextual = 1 << 8,
|
||||
Persistent = IncludeUndefined,
|
||||
}
|
||||
|
||||
// Indexed access types (TypeFlags.IndexedAccess)
|
||||
// Possible forms are T[xxx], xxx[T], or xxx[keyof T], where T is a type variable
|
||||
export interface IndexedAccessType extends InstantiableType {
|
||||
objectType: Type;
|
||||
indexType: Type;
|
||||
/**
|
||||
* @internal
|
||||
* Indicates that --noUncheckedIndexedAccess may introduce 'undefined' into
|
||||
* the resulting type, depending on how type variable constraints are resolved.
|
||||
*/
|
||||
noUncheckedIndexedAccessCandidate: boolean;
|
||||
/* @internal */
|
||||
accessFlags: AccessFlags; // Only includes AccessFlags.Persistent
|
||||
constraint?: Type;
|
||||
simplifiedForReading?: Type;
|
||||
simplifiedForWriting?: Type;
|
||||
|
||||
@ -149,4 +149,14 @@ tests/cases/conformance/controlFlow/controlFlowGenericTypes.ts(91,11): error TS2
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
// Repro from #44093
|
||||
|
||||
class EventEmitter<ET> {
|
||||
off<K extends keyof ET>(...args: [K, number] | [unknown, string]):void {}
|
||||
}
|
||||
function once<ET, T extends EventEmitter<ET>>(emittingObject: T, eventName: keyof ET): void {
|
||||
emittingObject.off(eventName, 0);
|
||||
emittingObject.off(eventName as typeof eventName, 0);
|
||||
}
|
||||
|
||||
@ -128,6 +128,16 @@ function get<K extends keyof A>(key: K, obj: A): number {
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
// Repro from #44093
|
||||
|
||||
class EventEmitter<ET> {
|
||||
off<K extends keyof ET>(...args: [K, number] | [unknown, string]):void {}
|
||||
}
|
||||
function once<ET, T extends EventEmitter<ET>>(emittingObject: T, eventName: keyof ET): void {
|
||||
emittingObject.off(eventName, 0);
|
||||
emittingObject.off(eventName as typeof eventName, 0);
|
||||
}
|
||||
|
||||
|
||||
//// [controlFlowGenericTypes.js]
|
||||
@ -220,3 +230,19 @@ function get(key, obj) {
|
||||
return 0;
|
||||
}
|
||||
;
|
||||
// Repro from #44093
|
||||
var EventEmitter = /** @class */ (function () {
|
||||
function EventEmitter() {
|
||||
}
|
||||
EventEmitter.prototype.off = function () {
|
||||
var args = [];
|
||||
for (var _i = 0; _i < arguments.length; _i++) {
|
||||
args[_i] = arguments[_i];
|
||||
}
|
||||
};
|
||||
return EventEmitter;
|
||||
}());
|
||||
function once(emittingObject, eventName) {
|
||||
emittingObject.off(eventName, 0);
|
||||
emittingObject.off(eventName, 0);
|
||||
}
|
||||
|
||||
@ -367,3 +367,41 @@ function get<K extends keyof A>(key: K, obj: A): number {
|
||||
return 0;
|
||||
};
|
||||
|
||||
// Repro from #44093
|
||||
|
||||
class EventEmitter<ET> {
|
||||
>EventEmitter : Symbol(EventEmitter, Decl(controlFlowGenericTypes.ts, 128, 2))
|
||||
>ET : Symbol(ET, Decl(controlFlowGenericTypes.ts, 132, 19))
|
||||
|
||||
off<K extends keyof ET>(...args: [K, number] | [unknown, string]):void {}
|
||||
>off : Symbol(EventEmitter.off, Decl(controlFlowGenericTypes.ts, 132, 24))
|
||||
>K : Symbol(K, Decl(controlFlowGenericTypes.ts, 133, 8))
|
||||
>ET : Symbol(ET, Decl(controlFlowGenericTypes.ts, 132, 19))
|
||||
>args : Symbol(args, Decl(controlFlowGenericTypes.ts, 133, 28))
|
||||
>K : Symbol(K, Decl(controlFlowGenericTypes.ts, 133, 8))
|
||||
}
|
||||
function once<ET, T extends EventEmitter<ET>>(emittingObject: T, eventName: keyof ET): void {
|
||||
>once : Symbol(once, Decl(controlFlowGenericTypes.ts, 134, 1))
|
||||
>ET : Symbol(ET, Decl(controlFlowGenericTypes.ts, 135, 14))
|
||||
>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 135, 17))
|
||||
>EventEmitter : Symbol(EventEmitter, Decl(controlFlowGenericTypes.ts, 128, 2))
|
||||
>ET : Symbol(ET, Decl(controlFlowGenericTypes.ts, 135, 14))
|
||||
>emittingObject : Symbol(emittingObject, Decl(controlFlowGenericTypes.ts, 135, 46))
|
||||
>T : Symbol(T, Decl(controlFlowGenericTypes.ts, 135, 17))
|
||||
>eventName : Symbol(eventName, Decl(controlFlowGenericTypes.ts, 135, 64))
|
||||
>ET : Symbol(ET, Decl(controlFlowGenericTypes.ts, 135, 14))
|
||||
|
||||
emittingObject.off(eventName, 0);
|
||||
>emittingObject.off : Symbol(EventEmitter.off, Decl(controlFlowGenericTypes.ts, 132, 24))
|
||||
>emittingObject : Symbol(emittingObject, Decl(controlFlowGenericTypes.ts, 135, 46))
|
||||
>off : Symbol(EventEmitter.off, Decl(controlFlowGenericTypes.ts, 132, 24))
|
||||
>eventName : Symbol(eventName, Decl(controlFlowGenericTypes.ts, 135, 64))
|
||||
|
||||
emittingObject.off(eventName as typeof eventName, 0);
|
||||
>emittingObject.off : Symbol(EventEmitter.off, Decl(controlFlowGenericTypes.ts, 132, 24))
|
||||
>emittingObject : Symbol(emittingObject, Decl(controlFlowGenericTypes.ts, 135, 46))
|
||||
>off : Symbol(EventEmitter.off, Decl(controlFlowGenericTypes.ts, 132, 24))
|
||||
>eventName : Symbol(eventName, Decl(controlFlowGenericTypes.ts, 135, 64))
|
||||
>eventName : Symbol(eventName, Decl(controlFlowGenericTypes.ts, 135, 64))
|
||||
}
|
||||
|
||||
|
||||
@ -355,3 +355,36 @@ function get<K extends keyof A>(key: K, obj: A): number {
|
||||
|
||||
};
|
||||
|
||||
// Repro from #44093
|
||||
|
||||
class EventEmitter<ET> {
|
||||
>EventEmitter : EventEmitter<ET>
|
||||
|
||||
off<K extends keyof ET>(...args: [K, number] | [unknown, string]):void {}
|
||||
>off : <K extends keyof ET>(...args: [K, number] | [unknown, string]) => void
|
||||
>args : [K, number] | [unknown, string]
|
||||
}
|
||||
function once<ET, T extends EventEmitter<ET>>(emittingObject: T, eventName: keyof ET): void {
|
||||
>once : <ET, T extends EventEmitter<ET>>(emittingObject: T, eventName: keyof ET) => void
|
||||
>emittingObject : T
|
||||
>eventName : keyof ET
|
||||
|
||||
emittingObject.off(eventName, 0);
|
||||
>emittingObject.off(eventName, 0) : void
|
||||
>emittingObject.off : <K extends keyof ET>(...args: [unknown, string] | [K, number]) => void
|
||||
>emittingObject : T
|
||||
>off : <K extends keyof ET>(...args: [unknown, string] | [K, number]) => void
|
||||
>eventName : keyof ET
|
||||
>0 : 0
|
||||
|
||||
emittingObject.off(eventName as typeof eventName, 0);
|
||||
>emittingObject.off(eventName as typeof eventName, 0) : void
|
||||
>emittingObject.off : <K extends keyof ET>(...args: [unknown, string] | [K, number]) => void
|
||||
>emittingObject : T
|
||||
>off : <K extends keyof ET>(...args: [unknown, string] | [K, number]) => void
|
||||
>eventName as typeof eventName : keyof ET
|
||||
>eventName : keyof ET
|
||||
>eventName : keyof ET
|
||||
>0 : 0
|
||||
}
|
||||
|
||||
|
||||
@ -129,3 +129,13 @@ function get<K extends keyof A>(key: K, obj: A): number {
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
// Repro from #44093
|
||||
|
||||
class EventEmitter<ET> {
|
||||
off<K extends keyof ET>(...args: [K, number] | [unknown, string]):void {}
|
||||
}
|
||||
function once<ET, T extends EventEmitter<ET>>(emittingObject: T, eventName: keyof ET): void {
|
||||
emittingObject.off(eventName, 0);
|
||||
emittingObject.off(eventName as typeof eventName, 0);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user