From 7bca43da7960e468a5cfc040b69fabd18460dfaa Mon Sep 17 00:00:00 2001 From: Gabriela Araujo Britto <gabrielaa@microsoft.com> Date: Thu, 6 Feb 2025 18:20:38 -0800 Subject: [PATCH] revert return type narrowing --- src/compiler/checker.ts | 377 +--- src/compiler/types.ts | 11 +- .../conditionalReturnExpression.errors.txt | 36 + .../conditionalReturnExpression.symbols | 63 + .../conditionalReturnExpression.types | 167 ++ .../reference/dependentReturnType1.errors.txt | 645 ------ .../reference/dependentReturnType1.symbols | 1386 ------------ .../reference/dependentReturnType1.types | 2008 ----------------- .../reference/dependentReturnType2.errors.txt | 314 --- .../reference/dependentReturnType2.symbols | 594 ----- .../reference/dependentReturnType2.types | 1007 --------- .../reference/dependentReturnType3.errors.txt | 224 -- .../reference/dependentReturnType3.symbols | 679 ------ .../reference/dependentReturnType3.types | 1000 -------- .../reference/dependentReturnType4.errors.txt | 40 - .../reference/dependentReturnType4.symbols | 76 - .../reference/dependentReturnType4.types | 95 - .../reference/dependentReturnType5.errors.txt | 109 - .../reference/dependentReturnType5.symbols | 220 -- .../reference/dependentReturnType5.types | 331 --- .../reference/dependentReturnType6.errors.txt | 193 -- .../reference/dependentReturnType6.symbols | 367 --- .../reference/dependentReturnType6.types | 512 ----- .../reference/dependentReturnType8.symbols | 30 - .../reference/dependentReturnType8.types | 38 - .../reference/dependentReturnType9.errors.txt | 71 - .../reference/dependentReturnType9.symbols | 173 -- .../reference/dependentReturnType9.types | 306 --- .../compiler/conditionalReturnExpression.ts | 24 + tests/cases/compiler/dependentReturnType1.ts | 519 ----- tests/cases/compiler/dependentReturnType2.ts | 307 --- tests/cases/compiler/dependentReturnType3.ts | 216 -- tests/cases/compiler/dependentReturnType4.ts | 36 - tests/cases/compiler/dependentReturnType5.ts | 99 - tests/cases/compiler/dependentReturnType6.ts | 137 -- tests/cases/compiler/dependentReturnType8.ts | 13 - tests/cases/compiler/dependentReturnType9.ts | 67 - .../returnTypeNarrowingAfterCachingTypes.ts | 12 - 38 files changed, 311 insertions(+), 12191 deletions(-) create mode 100644 tests/baselines/reference/conditionalReturnExpression.errors.txt create mode 100644 tests/baselines/reference/conditionalReturnExpression.symbols create mode 100644 tests/baselines/reference/conditionalReturnExpression.types delete mode 100644 tests/baselines/reference/dependentReturnType1.errors.txt delete mode 100644 tests/baselines/reference/dependentReturnType1.symbols delete mode 100644 tests/baselines/reference/dependentReturnType1.types delete mode 100644 tests/baselines/reference/dependentReturnType2.errors.txt delete mode 100644 tests/baselines/reference/dependentReturnType2.symbols delete mode 100644 tests/baselines/reference/dependentReturnType2.types delete mode 100644 tests/baselines/reference/dependentReturnType3.errors.txt delete mode 100644 tests/baselines/reference/dependentReturnType3.symbols delete mode 100644 tests/baselines/reference/dependentReturnType3.types delete mode 100644 tests/baselines/reference/dependentReturnType4.errors.txt delete mode 100644 tests/baselines/reference/dependentReturnType4.symbols delete mode 100644 tests/baselines/reference/dependentReturnType4.types delete mode 100644 tests/baselines/reference/dependentReturnType5.errors.txt delete mode 100644 tests/baselines/reference/dependentReturnType5.symbols delete mode 100644 tests/baselines/reference/dependentReturnType5.types delete mode 100644 tests/baselines/reference/dependentReturnType6.errors.txt delete mode 100644 tests/baselines/reference/dependentReturnType6.symbols delete mode 100644 tests/baselines/reference/dependentReturnType6.types delete mode 100644 tests/baselines/reference/dependentReturnType8.symbols delete mode 100644 tests/baselines/reference/dependentReturnType8.types delete mode 100644 tests/baselines/reference/dependentReturnType9.errors.txt delete mode 100644 tests/baselines/reference/dependentReturnType9.symbols delete mode 100644 tests/baselines/reference/dependentReturnType9.types create mode 100644 tests/cases/compiler/conditionalReturnExpression.ts delete mode 100644 tests/cases/compiler/dependentReturnType1.ts delete mode 100644 tests/cases/compiler/dependentReturnType2.ts delete mode 100644 tests/cases/compiler/dependentReturnType3.ts delete mode 100644 tests/cases/compiler/dependentReturnType4.ts delete mode 100644 tests/cases/compiler/dependentReturnType5.ts delete mode 100644 tests/cases/compiler/dependentReturnType6.ts delete mode 100644 tests/cases/compiler/dependentReturnType8.ts delete mode 100644 tests/cases/compiler/dependentReturnType9.ts delete mode 100644 tests/cases/fourslash/returnTypeNarrowingAfterCachingTypes.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index fcb93c45dc1dd..7a4370b2b52fc 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2381,7 +2381,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { [".json", ".json"], ]; - var narrowableReturnTypeCache = new Map<string, boolean>(); /* eslint-enable no-var */ initializeTypeChecker(); @@ -16630,18 +16629,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return !!(type.flags & TypeFlags.Substitution && (type as SubstitutionType).constraint.flags & TypeFlags.Unknown); } - function isNarrowingSubstitutionType(type: Type): boolean { - return !!(type.flags & TypeFlags.Substitution && (type as SubstitutionType).objectFlags & ObjectFlags.IsNarrowingType); - } - - function getSubstitutionType(baseType: Type, constraint: Type, isNarrowed?: boolean) { + function getSubstitutionType(baseType: Type, constraint: Type) { return constraint.flags & TypeFlags.AnyOrUnknown || constraint === baseType || baseType.flags & TypeFlags.Any ? baseType : - getOrCreateSubstitutionType(baseType, constraint, isNarrowed); + getOrCreateSubstitutionType(baseType, constraint); } - function getOrCreateSubstitutionType(baseType: Type, constraint: Type, isNarrowed?: boolean) { - const id = `${getTypeId(baseType)}>${getTypeId(constraint)}${isNarrowed ? ">N" : ""}`; + function getOrCreateSubstitutionType(baseType: Type, constraint: Type) { + const id = `${getTypeId(baseType)}>${getTypeId(constraint)}`; const cached = substitutionTypes.get(id); if (cached) { return cached; @@ -16649,9 +16644,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const result = createType(TypeFlags.Substitution) as SubstitutionType; result.baseType = baseType; result.constraint = constraint; - if (isNarrowed) { - result.objectFlags |= ObjectFlags.IsNarrowingType; - } substitutionTypes.set(id, result); return result; } @@ -19186,14 +19178,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return isGenericType(type) || checkTuples && isTupleType(type) && some(getElementTypes(type), isGenericType); } - function getConditionalType( - root: ConditionalRoot, - mapper: TypeMapper | undefined, - forConstraint: boolean, - aliasSymbol?: Symbol, - aliasTypeArguments?: readonly Type[], - forNarrowing?: boolean, - ): Type { + function getConditionalType(root: ConditionalRoot, mapper: TypeMapper | undefined, forConstraint: boolean, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]): Type { let result; let extraTypes: Type[] | undefined; let tailCount = 0; @@ -19215,9 +19200,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (checkType === wildcardType || extendsType === wildcardType) { return wildcardType; } - const effectiveCheckType = forNarrowing && isNarrowingSubstitutionType(checkType) - ? (checkType as SubstitutionType).constraint - : checkType; const checkTypeNode = skipTypeParentheses(root.node.checkType); const extendsTypeNode = skipTypeParentheses(root.node.extendsType); // When the check and extends types are simple tuple types of the same arity, we defer resolution of the @@ -19225,7 +19207,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // types can be written `[X] extends [Y] ? ...` and be deferred similarly to `X extends Y ? ...`. const checkTuples = isSimpleTupleType(checkTypeNode) && isSimpleTupleType(extendsTypeNode) && length((checkTypeNode as TupleTypeNode).elements) === length((extendsTypeNode as TupleTypeNode).elements); - const checkTypeDeferred = isDeferredType(effectiveCheckType, checkTuples); + const checkTypeDeferred = isDeferredType(checkType, checkTuples); let combinedMapper: TypeMapper | undefined; if (root.inferTypeParameters) { // When we're looking at making an inference for an infer type, when we get its constraint, it'll automagically be @@ -19261,17 +19243,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const inferredExtendsType = combinedMapper ? instantiateType(root.extendsType, combinedMapper) : extendsType; // We attempt to resolve the conditional type only when the check and extends types are non-generic if (!checkTypeDeferred && !isDeferredType(inferredExtendsType, checkTuples)) { - // Return falseType for a definitely false extends check. We check an instantiation of the two + // Return falseType for a definitely false extends check. We check an instantiations 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 instantiations will be and we can just return the false branch type. - if (!(inferredExtendsType.flags & TypeFlags.AnyOrUnknown) && (effectiveCheckType.flags & TypeFlags.Any || !isTypeAssignableTo(getPermissiveInstantiation(effectiveCheckType), getPermissiveInstantiation(inferredExtendsType)))) { + if (!(inferredExtendsType.flags & TypeFlags.AnyOrUnknown) && (checkType.flags & TypeFlags.Any || !isTypeAssignableTo(getPermissiveInstantiation(checkType), getPermissiveInstantiation(inferredExtendsType)))) { // Return union of trueType and falseType for 'any' since it matches anything. Furthermore, for a // distributive conditional type applied to the constraint of a type variable, include trueType if // there are possible values of the check type that are also possible values of the extends type. // We use a reverse assignability check as it is less expensive than the comparable relationship // and avoids false positives of a non-empty intersection check. - if (effectiveCheckType.flags & TypeFlags.Any || forConstraint && !(inferredExtendsType.flags & TypeFlags.Never) && someType(getPermissiveInstantiation(inferredExtendsType), t => isTypeAssignableTo(t, getPermissiveInstantiation(effectiveCheckType)))) { + if (checkType.flags & TypeFlags.Any || forConstraint && !(inferredExtendsType.flags & TypeFlags.Never) && someType(getPermissiveInstantiation(inferredExtendsType), t => isTypeAssignableTo(t, getPermissiveInstantiation(checkType)))) { (extraTypes || (extraTypes = [])).push(instantiateType(getTypeFromTypeNode(root.node.trueType), combinedMapper || mapper)); } // If falseType is an immediately nested conditional type that isn't distributive or has an @@ -19295,7 +19277,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // that has no constraint. This ensures that, for example, the type // type Foo<T extends { x: any }> = T extends { x: string } ? string : number // doesn't immediately resolve to 'string' instead of being deferred. - if (inferredExtendsType.flags & TypeFlags.AnyOrUnknown || isTypeAssignableTo(getRestrictiveInstantiation(effectiveCheckType), getRestrictiveInstantiation(inferredExtendsType))) { + if (inferredExtendsType.flags & TypeFlags.AnyOrUnknown || isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(inferredExtendsType))) { const trueType = getTypeFromTypeNode(root.node.trueType); const trueMapper = combinedMapper || mapper; if (canTailRecurse(trueType, trueMapper)) { @@ -20421,38 +20403,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!result) { const newMapper = createTypeMapper(root.outerTypeParameters, typeArguments); const checkType = root.checkType; - let distributionType = root.isDistributive ? getReducedType(getMappedType(checkType, newMapper)) : undefined; - let narrowingBaseType: Type | undefined; - const forNarrowing = distributionType && isNarrowingSubstitutionType(distributionType) && isNarrowableConditionalType(type, mapper); - if (forNarrowing) { - narrowingBaseType = (distributionType as SubstitutionType).baseType; - distributionType = getReducedType((distributionType as SubstitutionType).constraint); - } + const distributionType = root.isDistributive ? getReducedType(getMappedType(checkType, newMapper)) : undefined; // Distributive conditional types are distributed over union types. For example, when the // distributive conditional type T extends U ? X : Y is instantiated with A | B for T, the // result is (A extends U ? X : Y) | (B extends U ? X : Y). - if (distributionType && checkType !== distributionType && distributionType.flags & (TypeFlags.Union | TypeFlags.Never)) { - if (narrowingBaseType) { - result = mapTypeToIntersection( - distributionType, - (t: Type) => - getConditionalType( - root, - prependTypeMapping(checkType, getSubstitutionType(narrowingBaseType, t, /*isNarrowed*/ true), newMapper), - forConstraint, - /*aliasSymbol*/ undefined, - /*aliasTypeArguments*/ undefined, - forNarrowing, - ), - ); - } - else { - result = mapTypeWithAlias(distributionType, (t: Type) => getConditionalType(root, prependTypeMapping(checkType, t, newMapper), forConstraint), aliasSymbol, aliasTypeArguments); - } - } - else { - result = getConditionalType(root, newMapper, forConstraint, aliasSymbol, aliasTypeArguments, forNarrowing); - } + result = distributionType && checkType !== distributionType && distributionType.flags & (TypeFlags.Union | TypeFlags.Never) ? + mapTypeWithAlias(distributionType, t => getConditionalType(root, prependTypeMapping(checkType, t, newMapper), forConstraint), aliasSymbol, aliasTypeArguments) : + getConditionalType(root, newMapper, forConstraint, aliasSymbol, aliasTypeArguments); root.instantiations!.set(id, result); } return result; @@ -21773,12 +21730,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function shouldNormalizeIntersection(type: IntersectionType) { let hasInstantiable = false; let hasNullableOrEmpty = false; - let hasSubstitution = false; for (const t of type.types) { hasInstantiable ||= !!(t.flags & TypeFlags.Instantiable); hasNullableOrEmpty ||= !!(t.flags & TypeFlags.Nullable) || isEmptyAnonymousObjectType(t); - hasSubstitution ||= isNarrowingSubstitutionType(t); // This avoids displaying error messages with types like `T & T` when narrowing a return type - if (hasInstantiable && hasNullableOrEmpty || hasSubstitution) return true; + if (hasInstantiable && hasNullableOrEmpty) return true; } return false; } @@ -27963,23 +27918,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return changed ? mappedTypes && getUnionType(mappedTypes, noReductions ? UnionReduction.None : UnionReduction.Literal) : type; } - /** - * Similar to {@link mapType}, but creates an intersection with the result of mapping over a union type. - */ - function mapTypeToIntersection(type: Type, mapper: (t: Type) => Type): Type { - if (type.flags & TypeFlags.Never) { - return type; - } - if (!(type.flags & TypeFlags.Union)) { - return mapper(type); - } - const origin = (type as UnionType).origin; - const types = origin && origin.flags & TypeFlags.Union ? (origin as UnionType).types : (type as UnionType).types; - const mappedTypes = types.map(t => t.flags & TypeFlags.Union ? mapTypeToIntersection(t, mapper) : mapper(t)); - - return getIntersectionType(mappedTypes); - } - function mapTypeWithAlias(type: Type, mapper: (t: Type) => Type, aliasSymbol: Symbol | undefined, aliasTypeArguments: readonly Type[] | undefined) { return type.flags & TypeFlags.Union && aliasSymbol ? getUnionType(map((type as UnionType).types, mapper), UnionReduction.Literal, aliasSymbol, aliasTypeArguments) : @@ -29866,7 +29804,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return contextualType && !isGenericType(contextualType); } - function getNarrowableTypeForReference(type: Type, reference: Node, checkMode?: CheckMode, forReturnTypeNarrowing?: boolean) { + function getNarrowableTypeForReference(type: Type, reference: Node, checkMode?: CheckMode) { if (isNoInferType(type)) { type = (type as SubstitutionType).baseType; } @@ -29879,7 +29817,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // 'string | undefined' to give control flow analysis the opportunity to narrow to type 'string'. const substituteConstraints = !(checkMode && checkMode & CheckMode.Inferential) && someType(type, isGenericTypeWithUnionConstraint) && - (forReturnTypeNarrowing || isConstraintPosition(type, reference) || hasContextualTypeWithNoGenericTypes(reference, checkMode)); + (isConstraintPosition(type, reference) || hasContextualTypeWithNoGenericTypes(reference, checkMode)); return substituteConstraints ? mapType(type, getBaseConstraintOrType) : type; } @@ -31419,16 +31357,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getContextualTypeForReturnExpression(node: Expression, contextFlags: ContextFlags | undefined): Type | undefined { const func = getContainingFunction(node); if (func) { - const functionFlags = getFunctionFlags(func); - const links = getNodeLinks(node); - if (links.contextualReturnType) { - if (functionFlags & FunctionFlags.Async) { - return getUnionType([links.contextualReturnType, createPromiseLikeType(links.contextualReturnType)]); - } - return links.contextualReturnType; - } let contextualReturnType = getContextualReturnType(func, contextFlags); if (contextualReturnType) { + const functionFlags = getFunctionFlags(func); if (functionFlags & FunctionFlags.Generator) { // Generator or AsyncGenerator function const isAsyncGenerator = (functionFlags & FunctionFlags.Async) !== 0; if (contextualReturnType.flags & TypeFlags.Union) { @@ -32179,13 +32110,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (index >= 0) { return contextualTypes[index]; } - const links = getNodeLinks(node); - if (links.contextualReturnType) { - if (node.flags & NodeFlags.AwaitContext) { - return getUnionType([links.contextualReturnType, createPromiseLikeType(links.contextualReturnType)]); - } - return links.contextualReturnType; - } const { parent } = node; switch (parent.kind) { case SyntaxKind.VariableDeclaration: @@ -45868,270 +45792,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const effectiveExpr = expr && getEffectiveCheckNode(expr); // The effective expression for diagnostics purposes. const errorNode = inReturnStatement && !inConditionalExpression ? node : effectiveExpr; - // If the return type is not narrowable, we simply check if the return expression type is assignable to the return type. - if (!(unwrappedReturnType.flags & (TypeFlags.IndexedAccess | TypeFlags.Conditional)) || !couldContainTypeVariables(unwrappedReturnType)) { - checkTypeAssignableToAndOptionallyElaborate(unwrappedExprType, unwrappedReturnType, errorNode, effectiveExpr); - return; - } - - // If type of return expression is assignable to original return type, we don't need to narrow the return type. - if (checkTypeAssignableTo(unwrappedExprType, unwrappedReturnType, /*errorNode*/ undefined)) { - return; - } - - // There are two cases for obtaining a position in the control-flow graph on which references will be analyzed: - // - When the return expression is defined, and it is one of the two branches of a conditional expression, then the position is the expression itself: - // `function foo(...) { - // return cond ? |expr| : ... - // }` - // - When the return expression is undefined, or it is defined and it is not one of the branches of a conditional expression, then the position is the return statement itself: - // `function foo(...) { - // |return expr;| - // }` - // or - // `function foo(...) { - // |return;| - // }` - let narrowPosition: Node = node; - let narrowFlowNode = inReturnStatement && (node as ReturnStatement).flowNode; - if (expr && isConditionalExpression(expr.parent)) { - narrowFlowNode = expr.parent.whenTrue === expr ? expr.parent.flowNodeWhenTrue : expr.parent.flowNodeWhenFalse; - narrowPosition = expr; - } - - if (!narrowFlowNode) { - checkTypeAssignableToAndOptionallyElaborate(unwrappedExprType, unwrappedReturnType, errorNode, effectiveExpr); - return; - } - - const allTypeParameters = appendTypeParameters(getOuterTypeParameters(container, /*includeThisTypes*/ false), getEffectiveTypeParameterDeclarations(container as DeclarationWithTypeParameters)); - const narrowableTypeParameters = allTypeParameters && getNarrowableTypeParameters(allTypeParameters); - - if ( - !narrowableTypeParameters || - !narrowableTypeParameters.length || - !isNarrowableReturnType(unwrappedReturnType as ConditionalType | IndexedAccessType) - ) { - checkTypeAssignableToAndOptionallyElaborate(unwrappedExprType, unwrappedReturnType, errorNode, effectiveExpr); - return; - } - - const narrowedTypeParameters: TypeParameter[] = []; - const narrowedTypes: Type[] = []; - for (const [typeParam, symbol, reference] of narrowableTypeParameters) { - const narrowReference = factory.cloneNode(reference); // Construct a reference that can be narrowed. - // Don't reuse the original reference's node id, - // because that could cause us to get a type that was cached for the original reference. - narrowReference.id = undefined; - // Set the symbol of the synthetic reference. - // This allows us to get the type of the reference at a location where the reference is possibly shadowed. - getNodeLinks(narrowReference).resolvedSymbol = symbol; - setParent(narrowReference, narrowPosition.parent); - narrowReference.flowNode = narrowFlowNode; - const initialType = getNarrowableTypeForReference(typeParam, narrowReference, /*checkMode*/ undefined, /*forReturnTypeNarrowing*/ true); - if (initialType === typeParam) { - continue; - } - const flowType = getFlowTypeOfReference(narrowReference, initialType); - const exprType = getTypeFromFlowType(flowType); - // If attempting to narrow the expression type did not produce a narrower type, - // then discard this type parameter from narrowing. - if ( - exprType.flags & TypeFlags.AnyOrUnknown - || isErrorType(exprType) - || exprType === typeParam - || exprType === mapType(typeParam, getBaseConstraintOrType) - ) { - continue; - } - const narrowedType = getSubstitutionType(typeParam, exprType, /*isNarrowed*/ true); - narrowedTypeParameters.push(typeParam); - narrowedTypes.push(narrowedType); - } - - const narrowMapper = createTypeMapper(narrowedTypeParameters, narrowedTypes); - const narrowedReturnType = instantiateType( - unwrappedReturnType, - narrowMapper, - ); - - if (expr) { - const links = getNodeLinks(expr); - if (!links.contextualReturnType) { - links.contextualReturnType = narrowedReturnType; - } - } - - const narrowedExprType = expr ? checkExpression(expr) : undefinedType; - const narrowedUnwrappedExprType = functionFlags & FunctionFlags.Async - ? checkAwaitedType( - narrowedExprType, - /*withAlias*/ false, - node, - Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member, - ) - : narrowedExprType; - checkTypeAssignableToAndOptionallyElaborate(narrowedUnwrappedExprType, narrowedReturnType, errorNode, effectiveExpr); - } - - /** - * Narrowable type parameters are type parameters that: - * (1) have a union type constraint; - * (2) are used as the type of a single parameter in the function, and nothing else - */ - function getNarrowableTypeParameters(candidates: TypeParameter[]): [TypeParameter, Symbol, Identifier][] { - const narrowableParams: [TypeParameter, Symbol, Identifier][] = []; - for (const typeParam of candidates) { - const constraint = getConstraintOfTypeParameter(typeParam); - if (!constraint || !(constraint.flags & TypeFlags.Union)) continue; - if (typeParam.symbol && typeParam.symbol.declarations && typeParam.symbol.declarations.length === 1) { - const declaration = typeParam.symbol.declarations[0]; - const container = isJSDocTemplateTag(declaration.parent) ? getJSDocHost(declaration.parent) : declaration.parent; - if (!isFunctionLike(container)) continue; - let reference: Identifier | undefined; - let hasInvalidReference = false; - for (const paramDecl of container.parameters) { - const typeNode = getEffectiveTypeAnnotationNode(paramDecl); - if (!typeNode) continue; - if (isTypeParameterReferenced(typeParam, typeNode)) { - let candidateReference; - if ( - isTypeReferenceNode(typeNode) && - isReferenceToTypeParameter(typeParam, typeNode) && - (candidateReference = getValidParameterReference(paramDecl, constraint)) - ) { - // Type parameter has more than one valid reference. - if (reference) { - hasInvalidReference = true; - break; - } - reference = candidateReference; - } - else { // Type parameter has invalid reference. - hasInvalidReference = true; - break; - } - } - } - if (!hasInvalidReference && reference) { - const symbol = getResolvedSymbol(reference); - if (symbol !== unknownSymbol) narrowableParams.push([typeParam, symbol, reference]); - } - } - } - - return narrowableParams; - // For a parameter of declared type `T` to be a valid reference for narrowing, it must satisfy: - // - the parameter name is an identifier - // - if the parameter is optional, then `T`'s constraint must allow for undefined - function getValidParameterReference(paramDecl: ParameterDeclaration, constraint: Type): Identifier | undefined { - if (!isIdentifier(paramDecl.name)) return; - const isOptional = !!paramDecl.questionToken || isJSDocOptionalParameter(paramDecl); - if (isOptional && !containsUndefinedType(constraint)) return; - return paramDecl.name; - } - - function isReferenceToTypeParameter(typeParam: TypeParameter, node: TypeReferenceNode) { - return getTypeFromTypeReference(node) === typeParam; - } - - function isTypeParameterReferenced(typeParam: TypeParameter, node: TypeNode) { - return isReferenced(node); - - function isReferenced(node: Node): boolean { - if (isTypeReferenceNode(node)) { - return isReferenceToTypeParameter(typeParam, node); - } - if (isTypeQueryNode(node)) { - return isTypeParameterPossiblyReferenced(typeParam, node); - } - return !!forEachChild(node, isReferenced); - } - } - } - - function isNarrowableReturnType(returnType: IndexedAccessType | ConditionalType): boolean { - return isConditionalType(returnType) - ? isNarrowableConditionalType(returnType) - : !!(returnType.indexType.flags & TypeFlags.TypeParameter); - } - - function isNarrowableConditionalType(type: ConditionalType, mapper?: TypeMapper): boolean { - const typeArguments = mapper && map(type.root.outerTypeParameters, t => { - const mapped = getMappedType(t, mapper); - if (isNarrowingSubstitutionType(mapped)) { - return (mapped as SubstitutionType).baseType; - } - return mapped; - }); - const id = `${type.id}:${getTypeListId(typeArguments)}`; - let result = narrowableReturnTypeCache.get(id); - if (result === undefined) { - const nonNarrowingMapper = type.root.outerTypeParameters - && typeArguments - && createTypeMapper(type.root.outerTypeParameters, typeArguments); - const instantiatedType = instantiateType(type, nonNarrowingMapper); - result = isConditionalType(instantiatedType) && isNarrowableConditionalTypeWorker(instantiatedType); - narrowableReturnTypeCache.set(id, result); - } - return result; - } - - // A narrowable conditional type is one that has the following shape: - // `T extends A ? TrueBranch<T> : FalseBranch<T>`, in other words: - // (0) The conditional type is distributive; - // (1) The conditional type has no `infer` type parameters; - // (2) The conditional type's check type is a narrowable type parameter (i.e. a type parameter with a union constraint); - // (3) The extends type `A` is a type or a union of types belonging to the union constraint of the type parameter; - // (4) `TrueBranch<T>` and `FalseBranch<T>` must be valid, recursively. - // In particular, the false-most branch of the conditional type must be `never`. - function isNarrowableConditionalTypeWorker(type: ConditionalType): boolean { - // (0) - if (!type.root.isDistributive) { - return false; - } - // (1) - if (type.root.inferTypeParameters) { - return false; - } - - // (2) - if (!(type.checkType.flags & TypeFlags.TypeParameter)) { - return false; - } - - // (2) - const constraintType = getConstraintOfTypeParameter(type.checkType as TypeParameter); - if (!constraintType || !(constraintType.flags & TypeFlags.Union)) { - return false; - } - - // (3) - if ( - !everyType(type.extendsType, extendsType => - some( - (constraintType as UnionType).types, - constraintType => isTypeIdenticalTo(constraintType, extendsType), - )) - ) { - return false; - } - - // (4) - const trueType = getTrueTypeFromConditionalType(type); - const isValidTrueType = isConditionalType(trueType) - ? isNarrowableConditionalType(trueType) - : true; - if (!isValidTrueType) return false; - const falseType = getFalseTypeFromConditionalType(type); - const isValidFalseType = isConditionalType(falseType) - ? isNarrowableConditionalType(falseType) - : falseType === neverType; - return isValidFalseType; - } - - function isConditionalType(type: Type): type is ConditionalType { - return !!(type.flags & TypeFlags.Conditional); + checkTypeAssignableToAndOptionallyElaborate(unwrappedExprType, unwrappedReturnType, errorNode, effectiveExpr); } function checkWithStatement(node: WithStatement) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 449ad50cb014d..9cd1a9b9fc618 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -6249,7 +6249,6 @@ export interface NodeLinks { decoratorSignature?: Signature; // Signature for decorator as if invoked by the runtime. spreadIndices?: { first: number | undefined, last: number | undefined }; // Indices of first and last spread elements in array literal parameterInitializerContainsUndefined?: boolean; // True if this is a parameter declaration whose type annotation contains "undefined". - contextualReturnType?: Type; // If the node is a return statement's expression, then this is the contextual return type. fakeScopeForSignatureDeclaration?: "params" | "typeParams"; // If present, this is a fake scope injected into an enclosing declaration chain. assertionExpressionType?: Type; // Cached type of the expression of a type assertion potentialThisCollisions?: Node[]; @@ -6517,8 +6516,6 @@ export const enum ObjectFlags { IsGenericIndexType = 1 << 23, // Union or intersection contains generic index type /** @internal */ IsGenericType = IsGenericObjectType | IsGenericIndexType, - /** @internal */ - IsNarrowingType = 1 << 24, // Substitution type that comes from type narrowing // Flags that require TypeFlags.Union /** @internal */ @@ -6918,16 +6915,12 @@ export interface StringMappingType extends InstantiableType { } // Type parameter substitution (TypeFlags.Substitution) -// - Substitution types are created for type parameters or indexed access types that occur in the +// Substitution types are created for type parameters or indexed access types that occur in the // true branch of a conditional type. For example, in 'T extends string ? Foo<T> : Bar<T>', the // reference to T in Foo<T> is resolved as a substitution type that substitutes 'string & T' for T. // Thus, if Foo has a 'string' constraint on its type parameter, T will satisfy it. -// - Substitution types are also created for NoInfer<T> types. Those are represented as substitution +// Substitution type are also created for NoInfer<T> types. Those are represented as substitution // types where the constraint is type 'unknown' (which is never generated for the case above). -// - Substitution types are also created for return type narrowing: -// if a type parameter `T` is linked to a parameter `x` and `x`'s narrowed type is `S`, -// we represent that with a substitution type with base `T` and constraint `S`. -// The resulting substitution type has `ObjectFlags.IsNarrowedType` set. export interface SubstitutionType extends InstantiableType { objectFlags: ObjectFlags; baseType: Type; // Target type diff --git a/tests/baselines/reference/conditionalReturnExpression.errors.txt b/tests/baselines/reference/conditionalReturnExpression.errors.txt new file mode 100644 index 0000000000000..52dba11d81eb4 --- /dev/null +++ b/tests/baselines/reference/conditionalReturnExpression.errors.txt @@ -0,0 +1,36 @@ +conditionalReturnExpression.ts(2,18): error TS2322: Type '1' is not assignable to type '3'. +conditionalReturnExpression.ts(2,23): error TS2322: Type '2' is not assignable to type '3'. +conditionalReturnExpression.ts(8,43): error TS2322: Type 'number' is not assignable to type 'string'. +conditionalReturnExpression.ts(19,71): error TS2322: Type 'number' is not assignable to type 'string'. + + +==== conditionalReturnExpression.ts (4 errors) ==== + function return1(x: boolean): 3 { + return (x ? (1) : 2); + ~ +!!! error TS2322: Type '1' is not assignable to type '3'. + ~ +!!! error TS2322: Type '2' is not assignable to type '3'. + } + + declare function getAny(): any; + + function return2(x: string): string { + return x.startsWith("a") ? getAny() : 1; + ~ +!!! error TS2322: Type 'number' is not assignable to type 'string'. + } + + function return3(x: string): string { + return x.startsWith("a") ? "a" : x; + } + + function return4(x: string): string { + return (x.startsWith("a") ? getAny() : 1) as string; + } + + const return5 = (x: string): string => x.startsWith("a") ? getAny() : 1; + ~ +!!! error TS2322: Type 'number' is not assignable to type 'string'. + + const return6 = (x: string): string => (x.startsWith("a") ? getAny() : 1) as string; \ No newline at end of file diff --git a/tests/baselines/reference/conditionalReturnExpression.symbols b/tests/baselines/reference/conditionalReturnExpression.symbols new file mode 100644 index 0000000000000..266619261adc3 --- /dev/null +++ b/tests/baselines/reference/conditionalReturnExpression.symbols @@ -0,0 +1,63 @@ +//// [tests/cases/compiler/conditionalReturnExpression.ts] //// + +=== conditionalReturnExpression.ts === +function return1(x: boolean): 3 { +>return1 : Symbol(return1, Decl(conditionalReturnExpression.ts, 0, 0)) +>x : Symbol(x, Decl(conditionalReturnExpression.ts, 0, 17)) + + return (x ? (1) : 2); +>x : Symbol(x, Decl(conditionalReturnExpression.ts, 0, 17)) +} + +declare function getAny(): any; +>getAny : Symbol(getAny, Decl(conditionalReturnExpression.ts, 2, 1)) + +function return2(x: string): string { +>return2 : Symbol(return2, Decl(conditionalReturnExpression.ts, 4, 31)) +>x : Symbol(x, Decl(conditionalReturnExpression.ts, 6, 17)) + + return x.startsWith("a") ? getAny() : 1; +>x.startsWith : Symbol(String.startsWith, Decl(lib.es2015.core.d.ts, --, --)) +>x : Symbol(x, Decl(conditionalReturnExpression.ts, 6, 17)) +>startsWith : Symbol(String.startsWith, Decl(lib.es2015.core.d.ts, --, --)) +>getAny : Symbol(getAny, Decl(conditionalReturnExpression.ts, 2, 1)) +} + +function return3(x: string): string { +>return3 : Symbol(return3, Decl(conditionalReturnExpression.ts, 8, 1)) +>x : Symbol(x, Decl(conditionalReturnExpression.ts, 10, 17)) + + return x.startsWith("a") ? "a" : x; +>x.startsWith : Symbol(String.startsWith, Decl(lib.es2015.core.d.ts, --, --)) +>x : Symbol(x, Decl(conditionalReturnExpression.ts, 10, 17)) +>startsWith : Symbol(String.startsWith, Decl(lib.es2015.core.d.ts, --, --)) +>x : Symbol(x, Decl(conditionalReturnExpression.ts, 10, 17)) +} + +function return4(x: string): string { +>return4 : Symbol(return4, Decl(conditionalReturnExpression.ts, 12, 1)) +>x : Symbol(x, Decl(conditionalReturnExpression.ts, 14, 17)) + + return (x.startsWith("a") ? getAny() : 1) as string; +>x.startsWith : Symbol(String.startsWith, Decl(lib.es2015.core.d.ts, --, --)) +>x : Symbol(x, Decl(conditionalReturnExpression.ts, 14, 17)) +>startsWith : Symbol(String.startsWith, Decl(lib.es2015.core.d.ts, --, --)) +>getAny : Symbol(getAny, Decl(conditionalReturnExpression.ts, 2, 1)) +} + +const return5 = (x: string): string => x.startsWith("a") ? getAny() : 1; +>return5 : Symbol(return5, Decl(conditionalReturnExpression.ts, 18, 5)) +>x : Symbol(x, Decl(conditionalReturnExpression.ts, 18, 17)) +>x.startsWith : Symbol(String.startsWith, Decl(lib.es2015.core.d.ts, --, --)) +>x : Symbol(x, Decl(conditionalReturnExpression.ts, 18, 17)) +>startsWith : Symbol(String.startsWith, Decl(lib.es2015.core.d.ts, --, --)) +>getAny : Symbol(getAny, Decl(conditionalReturnExpression.ts, 2, 1)) + +const return6 = (x: string): string => (x.startsWith("a") ? getAny() : 1) as string; +>return6 : Symbol(return6, Decl(conditionalReturnExpression.ts, 20, 5)) +>x : Symbol(x, Decl(conditionalReturnExpression.ts, 20, 17)) +>x.startsWith : Symbol(String.startsWith, Decl(lib.es2015.core.d.ts, --, --)) +>x : Symbol(x, Decl(conditionalReturnExpression.ts, 20, 17)) +>startsWith : Symbol(String.startsWith, Decl(lib.es2015.core.d.ts, --, --)) +>getAny : Symbol(getAny, Decl(conditionalReturnExpression.ts, 2, 1)) + diff --git a/tests/baselines/reference/conditionalReturnExpression.types b/tests/baselines/reference/conditionalReturnExpression.types new file mode 100644 index 0000000000000..2dc26aa814086 --- /dev/null +++ b/tests/baselines/reference/conditionalReturnExpression.types @@ -0,0 +1,167 @@ +//// [tests/cases/compiler/conditionalReturnExpression.ts] //// + +=== conditionalReturnExpression.ts === +function return1(x: boolean): 3 { +>return1 : (x: boolean) => 3 +> : ^ ^^ ^^^^^ +>x : boolean +> : ^^^^^^^ + + return (x ? (1) : 2); +>(x ? (1) : 2) : 1 | 2 +> : ^^^^^ +>x ? (1) : 2 : 1 | 2 +> : ^^^^^ +>x : boolean +> : ^^^^^^^ +>(1) : 1 +> : ^ +>1 : 1 +> : ^ +>2 : 2 +> : ^ +} + +declare function getAny(): any; +>getAny : () => any +> : ^^^^^^ + +function return2(x: string): string { +>return2 : (x: string) => string +> : ^ ^^ ^^^^^ +>x : string +> : ^^^^^^ + + return x.startsWith("a") ? getAny() : 1; +>x.startsWith("a") ? getAny() : 1 : any +> : ^^^ +>x.startsWith("a") : boolean +> : ^^^^^^^ +>x.startsWith : (searchString: string, position?: number) => boolean +> : ^ ^^ ^^ ^^^ ^^^^^ +>x : string +> : ^^^^^^ +>startsWith : (searchString: string, position?: number) => boolean +> : ^ ^^ ^^ ^^^ ^^^^^ +>"a" : "a" +> : ^^^ +>getAny() : any +> : ^^^ +>getAny : () => any +> : ^^^^^^ +>1 : 1 +> : ^ +} + +function return3(x: string): string { +>return3 : (x: string) => string +> : ^ ^^ ^^^^^ +>x : string +> : ^^^^^^ + + return x.startsWith("a") ? "a" : x; +>x.startsWith("a") ? "a" : x : string +> : ^^^^^^ +>x.startsWith("a") : boolean +> : ^^^^^^^ +>x.startsWith : (searchString: string, position?: number) => boolean +> : ^ ^^ ^^ ^^^ ^^^^^ +>x : string +> : ^^^^^^ +>startsWith : (searchString: string, position?: number) => boolean +> : ^ ^^ ^^ ^^^ ^^^^^ +>"a" : "a" +> : ^^^ +>"a" : "a" +> : ^^^ +>x : string +> : ^^^^^^ +} + +function return4(x: string): string { +>return4 : (x: string) => string +> : ^ ^^ ^^^^^ +>x : string +> : ^^^^^^ + + return (x.startsWith("a") ? getAny() : 1) as string; +>(x.startsWith("a") ? getAny() : 1) as string : string +> : ^^^^^^ +>(x.startsWith("a") ? getAny() : 1) : any +> : ^^^ +>x.startsWith("a") ? getAny() : 1 : any +> : ^^^ +>x.startsWith("a") : boolean +> : ^^^^^^^ +>x.startsWith : (searchString: string, position?: number) => boolean +> : ^ ^^ ^^ ^^^ ^^^^^ +>x : string +> : ^^^^^^ +>startsWith : (searchString: string, position?: number) => boolean +> : ^ ^^ ^^ ^^^ ^^^^^ +>"a" : "a" +> : ^^^ +>getAny() : any +> : ^^^ +>getAny : () => any +> : ^^^^^^ +>1 : 1 +> : ^ +} + +const return5 = (x: string): string => x.startsWith("a") ? getAny() : 1; +>return5 : (x: string) => string +> : ^ ^^ ^^^^^ +>(x: string): string => x.startsWith("a") ? getAny() : 1 : (x: string) => string +> : ^ ^^ ^^^^^ +>x : string +> : ^^^^^^ +>x.startsWith("a") ? getAny() : 1 : any +> : ^^^ +>x.startsWith("a") : boolean +> : ^^^^^^^ +>x.startsWith : (searchString: string, position?: number) => boolean +> : ^ ^^ ^^ ^^^ ^^^^^ +>x : string +> : ^^^^^^ +>startsWith : (searchString: string, position?: number) => boolean +> : ^ ^^ ^^ ^^^ ^^^^^ +>"a" : "a" +> : ^^^ +>getAny() : any +> : ^^^ +>getAny : () => any +> : ^^^^^^ +>1 : 1 +> : ^ + +const return6 = (x: string): string => (x.startsWith("a") ? getAny() : 1) as string; +>return6 : (x: string) => string +> : ^ ^^ ^^^^^ +>(x: string): string => (x.startsWith("a") ? getAny() : 1) as string : (x: string) => string +> : ^ ^^ ^^^^^ +>x : string +> : ^^^^^^ +>(x.startsWith("a") ? getAny() : 1) as string : string +> : ^^^^^^ +>(x.startsWith("a") ? getAny() : 1) : any +> : ^^^ +>x.startsWith("a") ? getAny() : 1 : any +> : ^^^ +>x.startsWith("a") : boolean +> : ^^^^^^^ +>x.startsWith : (searchString: string, position?: number) => boolean +> : ^ ^^ ^^ ^^^ ^^^^^ +>x : string +> : ^^^^^^ +>startsWith : (searchString: string, position?: number) => boolean +> : ^ ^^ ^^ ^^^ ^^^^^ +>"a" : "a" +> : ^^^ +>getAny() : any +> : ^^^ +>getAny : () => any +> : ^^^^^^ +>1 : 1 +> : ^ + diff --git a/tests/baselines/reference/dependentReturnType1.errors.txt b/tests/baselines/reference/dependentReturnType1.errors.txt deleted file mode 100644 index 4513ccb75cf29..0000000000000 --- a/tests/baselines/reference/dependentReturnType1.errors.txt +++ /dev/null @@ -1,645 +0,0 @@ -dependentReturnType1.ts(11,9): error TS2322: Type 'number' is not assignable to type 'A[T]'. - Type 'number' is not assignable to type 'string'. -dependentReturnType1.ts(26,9): error TS2322: Type '""' is not assignable to type 'C[T]'. - Type '""' is not assignable to type 'never'. -dependentReturnType1.ts(35,9): error TS2322: Type '""' is not assignable to type 'never'. -dependentReturnType1.ts(69,9): error TS2322: Type '{ a: "a"; b: "b"; c: "c"; d: "d"; e: "e"; f: "f"; }' is not assignable to type 'T extends 1 ? One : T extends 2 ? Two : T extends 3 ? Three : Four'. -dependentReturnType1.ts(71,5): error TS2322: Type '{ a: "a"; b: "b"; c: "c"; d: "d"; e: "e"; f: "f"; g: "g"; }' is not assignable to type 'T extends 1 ? One : T extends 2 ? Two : T extends 3 ? Three : Four'. -dependentReturnType1.ts(80,22): error TS2353: Object literal may only specify known properties, and 'b' does not exist in type 'Three & Four'. -dependentReturnType1.ts(96,9): error TS2322: Type 'LeftOut' is not assignable to type 'Arg extends LeftIn ? LeftOut : Arg extends RightIn ? RightOut : never'. -dependentReturnType1.ts(98,9): error TS2322: Type 'RightOut' is not assignable to type 'Arg extends LeftIn ? LeftOut : Arg extends RightIn ? RightOut : never'. -dependentReturnType1.ts(115,9): error TS2322: Type 'number' is not assignable to type 'T extends Dog ? number : string'. -dependentReturnType1.ts(117,5): error TS2322: Type 'string' is not assignable to type 'T extends Dog ? number : string'. -dependentReturnType1.ts(152,13): error TS2322: Type 'string' is not assignable to type 'T extends string ? this : T extends undefined ? string : never'. -dependentReturnType1.ts(154,9): error TS2322: Type 'this' is not assignable to type 'T extends string ? this : T extends undefined ? string : never'. - Type 'Unnamed' is not assignable to type 'T extends string ? this : T extends undefined ? string : never'. -dependentReturnType1.ts(169,13): error TS2322: Type 'this' is not assignable to type 'string'. - Type 'Unnamed' is not assignable to type 'string'. -dependentReturnType1.ts(172,9): error TS2322: Type 'T & {}' is not assignable to type 'this'. - 'this' could be instantiated with an arbitrary type which could be unrelated to 'T & {}'. -dependentReturnType1.ts(206,24): error TS2322: Type 'string' is not assignable to type 'number'. -dependentReturnType1.ts(206,28): error TS2322: Type 'number' is not assignable to type 'string'. -dependentReturnType1.ts(243,9): error TS2322: Type '""' is not assignable to type 'T extends 1 | 2 ? T extends 1 ? string : T extends 2 ? boolean : never : T extends 3 ? number : never'. -dependentReturnType1.ts(245,9): error TS2322: Type 'true' is not assignable to type 'T extends 1 | 2 ? T extends 1 ? string : T extends 2 ? boolean : never : T extends 3 ? number : never'. -dependentReturnType1.ts(247,5): error TS2322: Type '3' is not assignable to type 'T extends 1 | 2 ? T extends 1 ? string : T extends 2 ? boolean : never : T extends 3 ? number : never'. -dependentReturnType1.ts(275,9): error TS2322: Type '1' is not assignable to type 'HelperCond<{ x: U; y: V; }, { x: string; y: true; }, 1, { x: number; y: false; }, 2>'. -dependentReturnType1.ts(278,9): error TS2322: Type '2' is not assignable to type 'HelperCond<{ x: U; y: V; }, { x: string; y: true; }, 1, { x: number; y: false; }, 2>'. -dependentReturnType1.ts(280,5): error TS2322: Type '0' is not assignable to type 'HelperCond<{ x: U; y: V; }, { x: string; y: true; }, 1, { x: number; y: false; }, 2>'. -dependentReturnType1.ts(302,9): error TS2322: Type 'string' is not assignable to type 'string[]'. -dependentReturnType1.ts(311,9): error TS2322: Type 'undefined' is not assignable to type 'T extends {} ? void : T extends undefined ? number : never'. -dependentReturnType1.ts(313,5): error TS2322: Type 'number' is not assignable to type 'T extends {} ? void : T extends undefined ? number : never'. -dependentReturnType1.ts(334,9): error TS2322: Type '1' is not assignable to type '4'. -dependentReturnType1.ts(367,13): error TS2322: Type 'number' is not assignable to type 'T extends 1 ? number : T extends 2 ? string : never'. -dependentReturnType1.ts(369,9): error TS2322: Type 'string' is not assignable to type 'T extends 1 ? number : T extends 2 ? string : never'. -dependentReturnType1.ts(392,9): error TS2322: Type '2' is not assignable to type 'T extends true ? 1 : T extends false ? 2 : never'. -dependentReturnType1.ts(402,13): error TS2322: Type 'number' is not assignable to type 'string'. -dependentReturnType1.ts(412,9): error TS2322: Type 'true' is not assignable to type 'T extends [infer R] ? R : T extends number ? boolean : never'. -dependentReturnType1.ts(414,5): error TS2322: Type '""' is not assignable to type 'T extends [infer R] ? R : T extends number ? boolean : never'. -dependentReturnType1.ts(439,15): error TS2322: Type '1' is not assignable to type 'T extends true ? 1 : T extends false ? 2 : never'. -dependentReturnType1.ts(441,11): error TS2322: Type '2' is not assignable to type 'T extends true ? 1 : T extends false ? 2 : never'. -dependentReturnType1.ts(470,13): error TS2322: Type 'R' is not assignable to type 'ConditionalReturnType<T, R, EOp>'. -dependentReturnType1.ts(472,13): error TS2322: Type 'R' is not assignable to type 'ConditionalReturnType<T, R, EOp>'. -dependentReturnType1.ts(474,13): error TS2322: Type 'T' is not assignable to type 'ConditionalReturnType<T, R, EOp>'. -dependentReturnType1.ts(488,9): error TS2322: Type 'R' is not assignable to type 'ConditionalReturnType<T, R, EOp>'. -dependentReturnType1.ts(514,5): error TS2322: Type '1' is not assignable to type 'never'. - - -==== dependentReturnType1.ts (39 errors) ==== - interface A { - 1: number; - 2: string; - } - - function f1<T extends 1 | 2>(x: T): A[T] { - if (x === 1) { - return 0; // Ok - } - else { - return 1; // Error - ~~~~~~ -!!! error TS2322: Type 'number' is not assignable to type 'A[T]'. -!!! error TS2322: Type 'number' is not assignable to type 'string'. - } - } - - interface C { - 1: number; - 2: string; - 3: boolean; - } - - function f2<T extends 1 | 2 | 3>(x: T): C[T] { - if (x === 1) { - return 0; // Ok - } - else { - return ""; // Error, returned expression needs to have type string & boolean (= never) - ~~~~~~ -!!! error TS2322: Type '""' is not assignable to type 'C[T]'. -!!! error TS2322: Type '""' is not assignable to type 'never'. - } - } - - function f3<T extends 1 | 2 | 3>(x: T): T extends 1 ? number : T extends 2 ? string : T extends 3 ? boolean : never { - if (x === 1) { - return 0; // Ok - } - else { - return ""; // Error, returned expression needs to have type string & boolean (= never) - ~~~~~~ -!!! error TS2322: Type '""' is not assignable to type 'never'. - } - } - - interface One { - a: "a"; - b: "b"; - c: "c"; - d: "d"; - } - - interface Two { - a: "a"; - b: "b"; - e: "e"; - f: "f"; - } - - interface Three { - a: "a"; - c: "c"; - e: "e"; - g: "g"; - } - - interface Four { - a: "a"; - d: "d"; - f: "f"; - g: "g"; - } - // Badly written conditional return type, will not trigger narrowing - function f10<T extends 1 | 2 | 3 | 4>(x: T): T extends 1 ? One : T extends 2 ? Two : T extends 3 ? Three : Four { - if (x === 1 || x === 2) { - return { a: "a", b: "b", c: "c", d: "d", e: "e", f: "f" }; // Error - ~~~~~~ -!!! error TS2322: Type '{ a: "a"; b: "b"; c: "c"; d: "d"; e: "e"; f: "f"; }' is not assignable to type 'T extends 1 ? One : T extends 2 ? Two : T extends 3 ? Three : Four'. - } - return { a: "a", b: "b", c: "c", d: "d", e: "e", f: "f", g: "g" }; // Error - ~~~~~~ -!!! error TS2322: Type '{ a: "a"; b: "b"; c: "c"; d: "d"; e: "e"; f: "f"; g: "g"; }' is not assignable to type 'T extends 1 ? One : T extends 2 ? Two : T extends 3 ? Three : Four'. - } - // Well written conditional - function f101<T extends 1 | 2 | 3 | 4>(x: T): T extends 1 ? One : T extends 2 ? Two : T extends 3 ? Three : T extends 4 ? Four : never { - if (x === 1 || x === 2) { - return { a: "a", b: "b", c: "c", d: "d", e: "e", f: "f" }; // Ok - } - // Excess property becomes a problem with the change, - // because we now check assignability to a narrower type... - return { a: "a", b: "b", c: "c", d: "d", e: "e", f: "f", g: "g" }; // EPC Error - ~ -!!! error TS2353: Object literal may only specify known properties, and 'b' does not exist in type 'Three & Four'. - } - - // This will not work for several reasons: - // - first because the constraint of type parameter `Arg` is generic, - // so attempting to narrow the type of `arg` in the `if` would result in type `Arg & LeftIn`, - // which when substituted in the conditional return type, would not further resolve that conditional type - // - second because the `else` branch would never work because we don't narrow the type of `arg` to `Arg & RightIn` - function conditionalProducingIf<LeftIn, RightIn, LeftOut, RightOut, Arg extends LeftIn | RightIn>( - arg: Arg, - cond: (arg: LeftIn | RightIn) => arg is LeftIn, - produceLeftOut: (arg: LeftIn) => LeftOut, - produceRightOut: (arg: RightIn) => RightOut): - Arg extends LeftIn ? LeftOut : Arg extends RightIn ? RightOut : never - { - if (cond(arg)) { - return produceLeftOut(arg); - ~~~~~~ -!!! error TS2322: Type 'LeftOut' is not assignable to type 'Arg extends LeftIn ? LeftOut : Arg extends RightIn ? RightOut : never'. - } else { - return produceRightOut(arg as RightIn); - ~~~~~~ -!!! error TS2322: Type 'RightOut' is not assignable to type 'Arg extends LeftIn ? LeftOut : Arg extends RightIn ? RightOut : never'. - } - } - - interface Animal { - name: string; - } - - interface Dog extends Animal { - bark: () => string; - } - - // This would be unsafe to narrow. - declare function isDog(x: Animal): x is Dog; - declare function doggy(x: Dog): number; - function f12<T extends Animal>(x: T): T extends Dog ? number : string { - if (isDog(x)) { // `x` has type `T & Dog` here - return doggy(x); - ~~~~~~ -!!! error TS2322: Type 'number' is not assignable to type 'T extends Dog ? number : string'. - } - return ""; // Error: Should not work because we can't express "not a Dog" in the type system - ~~~~~~ -!!! error TS2322: Type 'string' is not assignable to type 'T extends Dog ? number : string'. - } - - // Cannot narrow `keyof` too eagerly or something like the below breaks - function f<Entry extends { [index: string]: number | boolean }, EntryId extends keyof Entry>(entry: EntryId): Entry[EntryId] { - const entries = {} as Entry; - return entries[entry]; - } - - // Works the same as before - declare function takeA(val: 'A'): void; - export function bounceAndTakeIfA<AB extends 'A' | 'B'>(value: AB): AB { - if (value === 'A') { - takeA(value); - takeAB(value); - return value; - } - - return value; - function takeAB(val: AB): void {} - } - - // Works the same as before - export function bbb<AB extends "a" | "b">(value: AB): "a" { - if (value === "a") { - return value; - } - return "a"; - } - - class Unnamed { - root!: { name: string }; - // Error: No narrowing because parameter is optional but `T` doesn't allow for undefined - name<T extends string>(name?: T): T extends string ? this : T extends undefined ? string : never { - if (typeof name === 'undefined') { - return this.root.name; - ~~~~~~ -!!! error TS2322: Type 'string' is not assignable to type 'T extends string ? this : T extends undefined ? string : never'. - } - return this; - ~~~~~~ -!!! error TS2322: Type 'this' is not assignable to type 'T extends string ? this : T extends undefined ? string : never'. -!!! error TS2322: Type 'Unnamed' is not assignable to type 'T extends string ? this : T extends undefined ? string : never'. - } - - // Good conditional - name2<T extends string | undefined>(name?: T): T extends string ? this : T extends undefined ? string : never { - if (typeof name === 'undefined') { - return this.root.name; // Ok - } - this.root.name = name; - return this; // Ok - } - - // Good conditional, wrong return expressions - name3<T extends string | undefined>(name?: T): T extends string ? this : T extends undefined ? string : never { - if (typeof name === 'undefined') { - return this; // Error - ~~~~~~ -!!! error TS2322: Type 'this' is not assignable to type 'string'. -!!! error TS2322: Type 'Unnamed' is not assignable to type 'string'. - } - this.root.name = name; - return name; // Error - ~~~~~~ -!!! error TS2322: Type 'T & {}' is not assignable to type 'this'. -!!! error TS2322: 'this' could be instantiated with an arbitrary type which could be unrelated to 'T & {}'. - } - } - - // Conditional expressions - interface Aa { - 1: number; - 2: string; - 3: boolean; - } - - function trivialConditional<T extends 1 | 2 | 3>(x: T): Aa[T] { - if (x !== 1) { - return x === 2 ? "" : true; - } - else { - return 0; - } - } - - function conditional<T extends boolean>(x: T): - T extends true ? 1 : T extends false ? 2 : never { - return x ? 1 : 2; // Ok - } - - function contextualConditional<T extends "a" | "b">( - x: T - ): T extends "a" ? "a" : T extends "b" ? number : never { - return x === "a" ? x : parseInt(x); // Ok - } - - function conditionalWithError<T extends "a" | "b">( - x: T - ): T extends "a" ? number : T extends "b" ? string : never { - return x === "a" ? x : parseInt(x); // Error - ~ -!!! error TS2322: Type 'string' is not assignable to type 'number'. - ~~~~~~~~~~~ -!!! error TS2322: Type 'number' is not assignable to type 'string'. - } - - // Multiple indexed type reductions - interface BB { - "a": number; - [y: number]: string; - } - - interface AA<T extends keyof BB> { - "c": BB[T]; - "d": boolean, - } - - function reduction<T extends keyof BB, U extends "c" | "d">(x: T, y: U): AA<T>[U] { - if (y === "c" && x === "a") { - // AA<T>[U='c'] -> BB[T] - // BB[T='a'] -> number - return 0; // Ok - } - - return undefined as never; - } - - // Substitution types are not narrowed - function subsCond<T extends 1 | 2 | 3>( - x: T, - ): T extends 1 | 2 - ? T extends 1 - ? string - : T extends 2 - ? boolean - : never - : T extends 3 - ? number - : never { - if (x === 1) { - return ""; - ~~~~~~ -!!! error TS2322: Type '""' is not assignable to type 'T extends 1 | 2 ? T extends 1 ? string : T extends 2 ? boolean : never : T extends 3 ? number : never'. - } else if (x == 2) { - return true; - ~~~~~~ -!!! error TS2322: Type 'true' is not assignable to type 'T extends 1 | 2 ? T extends 1 ? string : T extends 2 ? boolean : never : T extends 3 ? number : never'. - } - return 3; - ~~~~~~ -!!! error TS2322: Type '3' is not assignable to type 'T extends 1 | 2 ? T extends 1 ? string : T extends 2 ? boolean : never : T extends 3 ? number : never'. - } - - - // Unsafe: check types overlap - declare function q(x: object): x is { b: number }; - function foo<T extends { a: string } | { b: number }>( - x: T, - ): T extends { a: string } ? number : T extends { b: number } ? string : never { - if (q(x)) { - x.b; - return ""; - } - x.a; - return 1; - } - - let y = { a: "", b: 1 } - const r = foo<{ a: string }>(y); // type says number but actually string - - type HelperCond<T, A, R1, B, R2> = T extends A ? R1 : T extends B ? R2 : never; - - // We don't narrow the return type because the conditionals are not distributive - function foo2<U extends string | number, V extends boolean>(x: U, y: V): - HelperCond<{ x: U, y: V }, - { x: string, y: true }, 1, - { x: number, y: false }, 2> { - if (typeof x === "string" && y === true) { - return 1; // Error - ~~~~~~ -!!! error TS2322: Type '1' is not assignable to type 'HelperCond<{ x: U; y: V; }, { x: string; y: true; }, 1, { x: number; y: false; }, 2>'. - } - if (typeof x === "number" && y === false) { - return 2; // Error - ~~~~~~ -!!! error TS2322: Type '2' is not assignable to type 'HelperCond<{ x: U; y: V; }, { x: string; y: true; }, 1, { x: number; y: false; }, 2>'. - } - return 0; // Error - ~~~~~~ -!!! error TS2322: Type '0' is not assignable to type 'HelperCond<{ x: U; y: V; }, { x: string; y: true; }, 1, { x: number; y: false; }, 2>'. - } - - // From https://github.com/microsoft/TypeScript/issues/24929#issue-332087943 - declare function isString(s: unknown): s is string; - // capitalize a string or each element of an array of strings - function capitalize<T extends string | string[]>( - input: T - ): T extends string[] ? string[] : T extends string ? string : never { - if (isString(input)) { - return input[0].toUpperCase() + input.slice(1); // Ok - } else { - return input.map(elt => capitalize(elt)); // Ok - } - } - - function badCapitalize<T extends string | string[]>( - input: T - ): T extends string[] ? string[] : T extends string ? string : never { - if (isString(input)) { - return input[0].toUpperCase() + input.slice(1); // Ok - } else { - return input[0].toUpperCase() + input.slice(1); // Bad, error - ~~~~~~ -!!! error TS2322: Type 'string' is not assignable to type 'string[]'. - } - } - - // No narrowing because conditional's extends type is different from type parameter constraint types - function voidRet<T extends { a: string } | undefined>( - x: T - ): T extends {} ? void : T extends undefined ? number : never { - if (x) { - return; - ~~~~~~ -!!! error TS2322: Type 'undefined' is not assignable to type 'T extends {} ? void : T extends undefined ? number : never'. - } - return 1; - ~~~~~~ -!!! error TS2322: Type 'number' is not assignable to type 'T extends {} ? void : T extends undefined ? number : never'. - } - - // Multiple type parameters at once - function woo<T extends string | number, U extends string | number>( - x: T, - y: U, - ): T extends string - ? U extends string - ? 1 - : U extends number - ? 2 - : never - : T extends number - ? U extends number - ? 3 - : U extends string - ? 4 - : never - : never { - if (typeof x === "number" && typeof y === "string") { - return 1; // Good error - ~~~~~~ -!!! error TS2322: Type '1' is not assignable to type '4'. - } - return undefined as any; - } - - function ttt<T extends string | number, U extends string | number>( - x: T, - y: U, - ): T extends string - ? U extends string - ? 1 - : U extends number - ? 2 - : never - : T extends number - ? U extends number - ? 3 - : U extends string - ? 4 - : never - : never { - if (typeof x === "number" && typeof y === "string") { - return 4; // Ok - } - - return undefined as any; - } - - // Shadowing of the narrowed reference - function shadowing<T extends 1 | 2>(x: T): T extends 1 ? number : T extends 2 ? string : never { - if (true) { - let x: number = Math.random() ? 1 : 2; - if (x === 1) { - return 1; // Error - ~~~~~~ -!!! error TS2322: Type 'number' is not assignable to type 'T extends 1 ? number : T extends 2 ? string : never'. - } - return ""; // Error - ~~~~~~ -!!! error TS2322: Type 'string' is not assignable to type 'T extends 1 ? number : T extends 2 ? string : never'. - } - } - - function noShadowing<T extends 1 | 2>(x: T): T extends 1 ? number : T extends 2 ? string : never { - if (true) { - if (x === 1) { - return 1; // Ok - } - return ""; // Ok - } - } - - // If the narrowing reference is out of scope, we simply won't narrow its type - declare let someX: boolean; - function scope2<T extends boolean>(a: T): T extends true ? 1 : T extends false ? 2 : never { - if ((true)) { - const someX = a; - if (someX) { // We narrow `someX` and the return type here - return 1; - } - } - if (!someX) { // This is a different `someX`, so we don't narrow here - return 2; - ~~~~~~ -!!! error TS2322: Type '2' is not assignable to type 'T extends true ? 1 : T extends false ? 2 : never'. - } - - return undefined as any; - } - - function moreShadowing<T extends 1 | 2>(x: T): T extends 1 ? number : T extends 2 ? string : never { - if (x === 2) { - let x: number = Math.random() ? 1 : 2; - if (x === 1) { - return 1; // Error - ~~~~~~ -!!! error TS2322: Type 'number' is not assignable to type 'string'. - } - return ""; // Ok - } - return 0; // Ok - } - - // This would be unsafe to narrow due to `infer` type. - function withInfer<T extends [string] | number>(x: T): T extends [infer R] ? R : T extends number ? boolean : never { - if (typeof x === "number") { - return true; - ~~~~~~ -!!! error TS2322: Type 'true' is not assignable to type 'T extends [infer R] ? R : T extends number ? boolean : never'. - } - return ""; - ~~~~~~ -!!! error TS2322: Type '""' is not assignable to type 'T extends [infer R] ? R : T extends number ? boolean : never'. - } - - const withInferResult = withInfer(["a"] as const); // The type says it returns `"a"`, but the function actually returns `""`. - - // Ok - async function abool<T extends true | false>(x: T): Promise<T extends true ? 1 : T extends false ? 2 : never> { - if (x) { - return 1; - } - return 2; - } - - // Ok - function* bbool<T extends true | false>(x: T): Generator<number, T extends true ? 1 : T extends false ? 2 : never, unknown> { - yield 3; - if (x) { - return 1; - } - return 2; - } - - // We don't do the same type of narrowing for `yield` statements - function* cbool<T extends true | false>(x: T): Generator<T extends true ? 1 : T extends false ? 2 : never, number, unknown> { - if (x) { - yield 1; - ~ -!!! error TS2322: Type '1' is not assignable to type 'T extends true ? 1 : T extends false ? 2 : never'. - } - yield 2; - ~ -!!! error TS2322: Type '2' is not assignable to type 'T extends true ? 1 : T extends false ? 2 : never'. - return 0; - } - - // From #33912 - abstract class Operation<T, R> { - abstract perform(t: T): R; - } - - type ConditionalReturnType<T, R, EOp extends Operation<T, R> | undefined> = - EOp extends Operation<T, R> ? R : EOp extends undefined ? T | R : never; - - - class ConditionalOperation< - T, - R, - EOp extends Operation<T, R> | undefined, - > extends Operation<T, ConditionalReturnType<T, R, EOp>> { - constructor( - private predicate: (value: T) => boolean, - private thenOp: Operation<T, R>, - private elseOp?: EOp, - ) { - super(); - } - - // We won't try to narrow the return type because `T` is declared on the class and we don't analyze this case. - perform(t: T): ConditionalReturnType<T, R, EOp> { - if (this.predicate(t)) { - return this.thenOp.perform(t); // Bad: this is assignable to all of the branches of the conditional, but we still can't return it - ~~~~~~ -!!! error TS2322: Type 'R' is not assignable to type 'ConditionalReturnType<T, R, EOp>'. - } else if (typeof this.elseOp !== "undefined") { - return this.elseOp.perform(t); // Would be ok - ~~~~~~ -!!! error TS2322: Type 'R' is not assignable to type 'ConditionalReturnType<T, R, EOp>'. - } else { - return t; // Would be ok - ~~~~~~ -!!! error TS2322: Type 'T' is not assignable to type 'ConditionalReturnType<T, R, EOp>'. - } - } - } - - // Like the version above, we will not attempt to narrow because there's more than one reference to `T`, - // because `T` shows up in the type of `predicate`. - function perform<T, R, EOp extends Operation<T, R> | undefined>( - t: T, - predicate: (value: T) => boolean, - thenOp: Operation<T, R>, - elseOp?: EOp, - ): ConditionalReturnType<T, R, EOp> { - if (predicate(t)) { - return thenOp.perform(t); // Bad: this is assignable to all of the branches of the conditional, but we still can't return it - ~~~~~~ -!!! error TS2322: Type 'R' is not assignable to type 'ConditionalReturnType<T, R, EOp>'. - } else if (elseOp !== undefined) { - return elseOp.perform(t); // Would be ok - } else { - return t; // Would be ok - } - } - - // Return conditional expressions with parentheses - function returnStuff1<T extends boolean>(x: T ): T extends true ? 1 : T extends false ? 2 : never { - return (x ? (1) : 2); - } - - function returnStuff2<T extends 1 | 2 | "a">(x: T ): - T extends 1 ? "one" : T extends 2 ? "two" : T extends "a" ? 0 : never { - return (typeof x === "string" ? 0 : (x === 1 ? ("one") : "two")); - } - - // If the conditional type's input is `never`, then it resolves to `never`: - function neverOk<T extends boolean>(x: T): T extends true ? 1 : T extends false ? 2 : never { - if (x === true) { - return 1; - } - if (x === false) { - return 2; - } - return 1; - ~~~~~~ -!!! error TS2322: Type '1' is not assignable to type 'never'. - } \ No newline at end of file diff --git a/tests/baselines/reference/dependentReturnType1.symbols b/tests/baselines/reference/dependentReturnType1.symbols deleted file mode 100644 index 11976eb81c5e6..0000000000000 --- a/tests/baselines/reference/dependentReturnType1.symbols +++ /dev/null @@ -1,1386 +0,0 @@ -//// [tests/cases/compiler/dependentReturnType1.ts] //// - -=== dependentReturnType1.ts === -interface A { ->A : Symbol(A, Decl(dependentReturnType1.ts, 0, 0)) - - 1: number; ->1 : Symbol(A[1], Decl(dependentReturnType1.ts, 0, 13)) - - 2: string; ->2 : Symbol(A[2], Decl(dependentReturnType1.ts, 1, 14)) -} - -function f1<T extends 1 | 2>(x: T): A[T] { ->f1 : Symbol(f1, Decl(dependentReturnType1.ts, 3, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 5, 12)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 5, 29)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 5, 12)) ->A : Symbol(A, Decl(dependentReturnType1.ts, 0, 0)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 5, 12)) - - if (x === 1) { ->x : Symbol(x, Decl(dependentReturnType1.ts, 5, 29)) - - return 0; // Ok - } - else { - return 1; // Error - } -} - -interface C { ->C : Symbol(C, Decl(dependentReturnType1.ts, 12, 1)) - - 1: number; ->1 : Symbol(C[1], Decl(dependentReturnType1.ts, 14, 13)) - - 2: string; ->2 : Symbol(C[2], Decl(dependentReturnType1.ts, 15, 14)) - - 3: boolean; ->3 : Symbol(C[3], Decl(dependentReturnType1.ts, 16, 14)) -} - -function f2<T extends 1 | 2 | 3>(x: T): C[T] { ->f2 : Symbol(f2, Decl(dependentReturnType1.ts, 18, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 20, 12)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 20, 33)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 20, 12)) ->C : Symbol(C, Decl(dependentReturnType1.ts, 12, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 20, 12)) - - if (x === 1) { ->x : Symbol(x, Decl(dependentReturnType1.ts, 20, 33)) - - return 0; // Ok - } - else { - return ""; // Error, returned expression needs to have type string & boolean (= never) - } -} - -function f3<T extends 1 | 2 | 3>(x: T): T extends 1 ? number : T extends 2 ? string : T extends 3 ? boolean : never { ->f3 : Symbol(f3, Decl(dependentReturnType1.ts, 27, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 29, 12)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 29, 33)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 29, 12)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 29, 12)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 29, 12)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 29, 12)) - - if (x === 1) { ->x : Symbol(x, Decl(dependentReturnType1.ts, 29, 33)) - - return 0; // Ok - } - else { - return ""; // Error, returned expression needs to have type string & boolean (= never) - } -} - -interface One { ->One : Symbol(One, Decl(dependentReturnType1.ts, 36, 1)) - - a: "a"; ->a : Symbol(One.a, Decl(dependentReturnType1.ts, 38, 15)) - - b: "b"; ->b : Symbol(One.b, Decl(dependentReturnType1.ts, 39, 11)) - - c: "c"; ->c : Symbol(One.c, Decl(dependentReturnType1.ts, 40, 11)) - - d: "d"; ->d : Symbol(One.d, Decl(dependentReturnType1.ts, 41, 11)) -} - -interface Two { ->Two : Symbol(Two, Decl(dependentReturnType1.ts, 43, 1)) - - a: "a"; ->a : Symbol(Two.a, Decl(dependentReturnType1.ts, 45, 15)) - - b: "b"; ->b : Symbol(Two.b, Decl(dependentReturnType1.ts, 46, 11)) - - e: "e"; ->e : Symbol(Two.e, Decl(dependentReturnType1.ts, 47, 11)) - - f: "f"; ->f : Symbol(Two.f, Decl(dependentReturnType1.ts, 48, 11)) -} - -interface Three { ->Three : Symbol(Three, Decl(dependentReturnType1.ts, 50, 1)) - - a: "a"; ->a : Symbol(Three.a, Decl(dependentReturnType1.ts, 52, 17)) - - c: "c"; ->c : Symbol(Three.c, Decl(dependentReturnType1.ts, 53, 11)) - - e: "e"; ->e : Symbol(Three.e, Decl(dependentReturnType1.ts, 54, 11)) - - g: "g"; ->g : Symbol(Three.g, Decl(dependentReturnType1.ts, 55, 11)) -} - -interface Four { ->Four : Symbol(Four, Decl(dependentReturnType1.ts, 57, 1)) - - a: "a"; ->a : Symbol(Four.a, Decl(dependentReturnType1.ts, 59, 16)) - - d: "d"; ->d : Symbol(Four.d, Decl(dependentReturnType1.ts, 60, 11)) - - f: "f"; ->f : Symbol(Four.f, Decl(dependentReturnType1.ts, 61, 11)) - - g: "g"; ->g : Symbol(Four.g, Decl(dependentReturnType1.ts, 62, 11)) -} -// Badly written conditional return type, will not trigger narrowing -function f10<T extends 1 | 2 | 3 | 4>(x: T): T extends 1 ? One : T extends 2 ? Two : T extends 3 ? Three : Four { ->f10 : Symbol(f10, Decl(dependentReturnType1.ts, 64, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 66, 13)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 66, 38)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 66, 13)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 66, 13)) ->One : Symbol(One, Decl(dependentReturnType1.ts, 36, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 66, 13)) ->Two : Symbol(Two, Decl(dependentReturnType1.ts, 43, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 66, 13)) ->Three : Symbol(Three, Decl(dependentReturnType1.ts, 50, 1)) ->Four : Symbol(Four, Decl(dependentReturnType1.ts, 57, 1)) - - if (x === 1 || x === 2) { ->x : Symbol(x, Decl(dependentReturnType1.ts, 66, 38)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 66, 38)) - - return { a: "a", b: "b", c: "c", d: "d", e: "e", f: "f" }; // Error ->a : Symbol(a, Decl(dependentReturnType1.ts, 68, 16)) ->b : Symbol(b, Decl(dependentReturnType1.ts, 68, 24)) ->c : Symbol(c, Decl(dependentReturnType1.ts, 68, 32)) ->d : Symbol(d, Decl(dependentReturnType1.ts, 68, 40)) ->e : Symbol(e, Decl(dependentReturnType1.ts, 68, 48)) ->f : Symbol(f, Decl(dependentReturnType1.ts, 68, 56)) - } - return { a: "a", b: "b", c: "c", d: "d", e: "e", f: "f", g: "g" }; // Error ->a : Symbol(a, Decl(dependentReturnType1.ts, 70, 12)) ->b : Symbol(b, Decl(dependentReturnType1.ts, 70, 20)) ->c : Symbol(c, Decl(dependentReturnType1.ts, 70, 28)) ->d : Symbol(d, Decl(dependentReturnType1.ts, 70, 36)) ->e : Symbol(e, Decl(dependentReturnType1.ts, 70, 44)) ->f : Symbol(f, Decl(dependentReturnType1.ts, 70, 52)) ->g : Symbol(g, Decl(dependentReturnType1.ts, 70, 60)) -} -// Well written conditional -function f101<T extends 1 | 2 | 3 | 4>(x: T): T extends 1 ? One : T extends 2 ? Two : T extends 3 ? Three : T extends 4 ? Four : never { ->f101 : Symbol(f101, Decl(dependentReturnType1.ts, 71, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 73, 14)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 73, 39)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 73, 14)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 73, 14)) ->One : Symbol(One, Decl(dependentReturnType1.ts, 36, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 73, 14)) ->Two : Symbol(Two, Decl(dependentReturnType1.ts, 43, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 73, 14)) ->Three : Symbol(Three, Decl(dependentReturnType1.ts, 50, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 73, 14)) ->Four : Symbol(Four, Decl(dependentReturnType1.ts, 57, 1)) - - if (x === 1 || x === 2) { ->x : Symbol(x, Decl(dependentReturnType1.ts, 73, 39)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 73, 39)) - - return { a: "a", b: "b", c: "c", d: "d", e: "e", f: "f" }; // Ok ->a : Symbol(a, Decl(dependentReturnType1.ts, 75, 16)) ->b : Symbol(b, Decl(dependentReturnType1.ts, 75, 24)) ->c : Symbol(c, Decl(dependentReturnType1.ts, 75, 32)) ->d : Symbol(d, Decl(dependentReturnType1.ts, 75, 40)) ->e : Symbol(e, Decl(dependentReturnType1.ts, 75, 48)) ->f : Symbol(f, Decl(dependentReturnType1.ts, 75, 56)) - } - // Excess property becomes a problem with the change, - // because we now check assignability to a narrower type... - return { a: "a", b: "b", c: "c", d: "d", e: "e", f: "f", g: "g" }; // EPC Error ->a : Symbol(a, Decl(dependentReturnType1.ts, 79, 12)) ->b : Symbol(b, Decl(dependentReturnType1.ts, 79, 20)) ->c : Symbol(c, Decl(dependentReturnType1.ts, 79, 28)) ->d : Symbol(d, Decl(dependentReturnType1.ts, 79, 36)) ->e : Symbol(e, Decl(dependentReturnType1.ts, 79, 44)) ->f : Symbol(f, Decl(dependentReturnType1.ts, 79, 52)) ->g : Symbol(g, Decl(dependentReturnType1.ts, 79, 60)) -} - -// This will not work for several reasons: -// - first because the constraint of type parameter `Arg` is generic, -// so attempting to narrow the type of `arg` in the `if` would result in type `Arg & LeftIn`, -// which when substituted in the conditional return type, would not further resolve that conditional type -// - second because the `else` branch would never work because we don't narrow the type of `arg` to `Arg & RightIn` -function conditionalProducingIf<LeftIn, RightIn, LeftOut, RightOut, Arg extends LeftIn | RightIn>( ->conditionalProducingIf : Symbol(conditionalProducingIf, Decl(dependentReturnType1.ts, 80, 1)) ->LeftIn : Symbol(LeftIn, Decl(dependentReturnType1.ts, 87, 32)) ->RightIn : Symbol(RightIn, Decl(dependentReturnType1.ts, 87, 39)) ->LeftOut : Symbol(LeftOut, Decl(dependentReturnType1.ts, 87, 48)) ->RightOut : Symbol(RightOut, Decl(dependentReturnType1.ts, 87, 57)) ->Arg : Symbol(Arg, Decl(dependentReturnType1.ts, 87, 67)) ->LeftIn : Symbol(LeftIn, Decl(dependentReturnType1.ts, 87, 32)) ->RightIn : Symbol(RightIn, Decl(dependentReturnType1.ts, 87, 39)) - - arg: Arg, ->arg : Symbol(arg, Decl(dependentReturnType1.ts, 87, 98)) ->Arg : Symbol(Arg, Decl(dependentReturnType1.ts, 87, 67)) - - cond: (arg: LeftIn | RightIn) => arg is LeftIn, ->cond : Symbol(cond, Decl(dependentReturnType1.ts, 88, 13)) ->arg : Symbol(arg, Decl(dependentReturnType1.ts, 89, 11)) ->LeftIn : Symbol(LeftIn, Decl(dependentReturnType1.ts, 87, 32)) ->RightIn : Symbol(RightIn, Decl(dependentReturnType1.ts, 87, 39)) ->arg : Symbol(arg, Decl(dependentReturnType1.ts, 89, 11)) ->LeftIn : Symbol(LeftIn, Decl(dependentReturnType1.ts, 87, 32)) - - produceLeftOut: (arg: LeftIn) => LeftOut, ->produceLeftOut : Symbol(produceLeftOut, Decl(dependentReturnType1.ts, 89, 51)) ->arg : Symbol(arg, Decl(dependentReturnType1.ts, 90, 21)) ->LeftIn : Symbol(LeftIn, Decl(dependentReturnType1.ts, 87, 32)) ->LeftOut : Symbol(LeftOut, Decl(dependentReturnType1.ts, 87, 48)) - - produceRightOut: (arg: RightIn) => RightOut): ->produceRightOut : Symbol(produceRightOut, Decl(dependentReturnType1.ts, 90, 45)) ->arg : Symbol(arg, Decl(dependentReturnType1.ts, 91, 22)) ->RightIn : Symbol(RightIn, Decl(dependentReturnType1.ts, 87, 39)) ->RightOut : Symbol(RightOut, Decl(dependentReturnType1.ts, 87, 57)) - - Arg extends LeftIn ? LeftOut : Arg extends RightIn ? RightOut : never ->Arg : Symbol(Arg, Decl(dependentReturnType1.ts, 87, 67)) ->LeftIn : Symbol(LeftIn, Decl(dependentReturnType1.ts, 87, 32)) ->LeftOut : Symbol(LeftOut, Decl(dependentReturnType1.ts, 87, 48)) ->Arg : Symbol(Arg, Decl(dependentReturnType1.ts, 87, 67)) ->RightIn : Symbol(RightIn, Decl(dependentReturnType1.ts, 87, 39)) ->RightOut : Symbol(RightOut, Decl(dependentReturnType1.ts, 87, 57)) -{ - if (cond(arg)) { ->cond : Symbol(cond, Decl(dependentReturnType1.ts, 88, 13)) ->arg : Symbol(arg, Decl(dependentReturnType1.ts, 87, 98)) - - return produceLeftOut(arg); ->produceLeftOut : Symbol(produceLeftOut, Decl(dependentReturnType1.ts, 89, 51)) ->arg : Symbol(arg, Decl(dependentReturnType1.ts, 87, 98)) - - } else { - return produceRightOut(arg as RightIn); ->produceRightOut : Symbol(produceRightOut, Decl(dependentReturnType1.ts, 90, 45)) ->arg : Symbol(arg, Decl(dependentReturnType1.ts, 87, 98)) ->RightIn : Symbol(RightIn, Decl(dependentReturnType1.ts, 87, 39)) - } -} - -interface Animal { ->Animal : Symbol(Animal, Decl(dependentReturnType1.ts, 99, 1)) - - name: string; ->name : Symbol(Animal.name, Decl(dependentReturnType1.ts, 101, 18)) -} - -interface Dog extends Animal { ->Dog : Symbol(Dog, Decl(dependentReturnType1.ts, 103, 1)) ->Animal : Symbol(Animal, Decl(dependentReturnType1.ts, 99, 1)) - - bark: () => string; ->bark : Symbol(Dog.bark, Decl(dependentReturnType1.ts, 105, 30)) -} - -// This would be unsafe to narrow. -declare function isDog(x: Animal): x is Dog; ->isDog : Symbol(isDog, Decl(dependentReturnType1.ts, 107, 1)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 110, 23)) ->Animal : Symbol(Animal, Decl(dependentReturnType1.ts, 99, 1)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 110, 23)) ->Dog : Symbol(Dog, Decl(dependentReturnType1.ts, 103, 1)) - -declare function doggy(x: Dog): number; ->doggy : Symbol(doggy, Decl(dependentReturnType1.ts, 110, 44)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 111, 23)) ->Dog : Symbol(Dog, Decl(dependentReturnType1.ts, 103, 1)) - -function f12<T extends Animal>(x: T): T extends Dog ? number : string { ->f12 : Symbol(f12, Decl(dependentReturnType1.ts, 111, 39)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 112, 13)) ->Animal : Symbol(Animal, Decl(dependentReturnType1.ts, 99, 1)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 112, 31)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 112, 13)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 112, 13)) ->Dog : Symbol(Dog, Decl(dependentReturnType1.ts, 103, 1)) - - if (isDog(x)) { // `x` has type `T & Dog` here ->isDog : Symbol(isDog, Decl(dependentReturnType1.ts, 107, 1)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 112, 31)) - - return doggy(x); ->doggy : Symbol(doggy, Decl(dependentReturnType1.ts, 110, 44)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 112, 31)) - } - return ""; // Error: Should not work because we can't express "not a Dog" in the type system -} - -// Cannot narrow `keyof` too eagerly or something like the below breaks -function f<Entry extends { [index: string]: number | boolean }, EntryId extends keyof Entry>(entry: EntryId): Entry[EntryId] { ->f : Symbol(f, Decl(dependentReturnType1.ts, 117, 1)) ->Entry : Symbol(Entry, Decl(dependentReturnType1.ts, 120, 11)) ->index : Symbol(index, Decl(dependentReturnType1.ts, 120, 28)) ->EntryId : Symbol(EntryId, Decl(dependentReturnType1.ts, 120, 63)) ->Entry : Symbol(Entry, Decl(dependentReturnType1.ts, 120, 11)) ->entry : Symbol(entry, Decl(dependentReturnType1.ts, 120, 93)) ->EntryId : Symbol(EntryId, Decl(dependentReturnType1.ts, 120, 63)) ->Entry : Symbol(Entry, Decl(dependentReturnType1.ts, 120, 11)) ->EntryId : Symbol(EntryId, Decl(dependentReturnType1.ts, 120, 63)) - - const entries = {} as Entry; ->entries : Symbol(entries, Decl(dependentReturnType1.ts, 121, 9)) ->Entry : Symbol(Entry, Decl(dependentReturnType1.ts, 120, 11)) - - return entries[entry]; ->entries : Symbol(entries, Decl(dependentReturnType1.ts, 121, 9)) ->entry : Symbol(entry, Decl(dependentReturnType1.ts, 120, 93)) -} - -// Works the same as before -declare function takeA(val: 'A'): void; ->takeA : Symbol(takeA, Decl(dependentReturnType1.ts, 123, 1)) ->val : Symbol(val, Decl(dependentReturnType1.ts, 126, 23)) - -export function bounceAndTakeIfA<AB extends 'A' | 'B'>(value: AB): AB { ->bounceAndTakeIfA : Symbol(bounceAndTakeIfA, Decl(dependentReturnType1.ts, 126, 39)) ->AB : Symbol(AB, Decl(dependentReturnType1.ts, 127, 33)) ->value : Symbol(value, Decl(dependentReturnType1.ts, 127, 55)) ->AB : Symbol(AB, Decl(dependentReturnType1.ts, 127, 33)) ->AB : Symbol(AB, Decl(dependentReturnType1.ts, 127, 33)) - - if (value === 'A') { ->value : Symbol(value, Decl(dependentReturnType1.ts, 127, 55)) - - takeA(value); ->takeA : Symbol(takeA, Decl(dependentReturnType1.ts, 123, 1)) ->value : Symbol(value, Decl(dependentReturnType1.ts, 127, 55)) - - takeAB(value); ->takeAB : Symbol(takeAB, Decl(dependentReturnType1.ts, 134, 17)) ->value : Symbol(value, Decl(dependentReturnType1.ts, 127, 55)) - - return value; ->value : Symbol(value, Decl(dependentReturnType1.ts, 127, 55)) - } - - return value; ->value : Symbol(value, Decl(dependentReturnType1.ts, 127, 55)) - - function takeAB(val: AB): void {} ->takeAB : Symbol(takeAB, Decl(dependentReturnType1.ts, 134, 17)) ->val : Symbol(val, Decl(dependentReturnType1.ts, 135, 20)) ->AB : Symbol(AB, Decl(dependentReturnType1.ts, 127, 33)) -} - -// Works the same as before -export function bbb<AB extends "a" | "b">(value: AB): "a" { ->bbb : Symbol(bbb, Decl(dependentReturnType1.ts, 136, 1)) ->AB : Symbol(AB, Decl(dependentReturnType1.ts, 139, 20)) ->value : Symbol(value, Decl(dependentReturnType1.ts, 139, 42)) ->AB : Symbol(AB, Decl(dependentReturnType1.ts, 139, 20)) - - if (value === "a") { ->value : Symbol(value, Decl(dependentReturnType1.ts, 139, 42)) - - return value; ->value : Symbol(value, Decl(dependentReturnType1.ts, 139, 42)) - } - return "a"; -} - -class Unnamed { ->Unnamed : Symbol(Unnamed, Decl(dependentReturnType1.ts, 144, 1)) - - root!: { name: string }; ->root : Symbol(Unnamed.root, Decl(dependentReturnType1.ts, 146, 15)) ->name : Symbol(name, Decl(dependentReturnType1.ts, 147, 12)) - - // Error: No narrowing because parameter is optional but `T` doesn't allow for undefined - name<T extends string>(name?: T): T extends string ? this : T extends undefined ? string : never { ->name : Symbol(Unnamed.name, Decl(dependentReturnType1.ts, 147, 28)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 149, 9)) ->name : Symbol(name, Decl(dependentReturnType1.ts, 149, 27)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 149, 9)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 149, 9)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 149, 9)) - - if (typeof name === 'undefined') { ->name : Symbol(name, Decl(dependentReturnType1.ts, 149, 27)) - - return this.root.name; ->this.root.name : Symbol(name, Decl(dependentReturnType1.ts, 147, 12)) ->this.root : Symbol(Unnamed.root, Decl(dependentReturnType1.ts, 146, 15)) ->this : Symbol(Unnamed, Decl(dependentReturnType1.ts, 144, 1)) ->root : Symbol(Unnamed.root, Decl(dependentReturnType1.ts, 146, 15)) ->name : Symbol(name, Decl(dependentReturnType1.ts, 147, 12)) - } - return this; ->this : Symbol(Unnamed, Decl(dependentReturnType1.ts, 144, 1)) - } - - // Good conditional - name2<T extends string | undefined>(name?: T): T extends string ? this : T extends undefined ? string : never { ->name2 : Symbol(Unnamed.name2, Decl(dependentReturnType1.ts, 154, 5)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 157, 10)) ->name : Symbol(name, Decl(dependentReturnType1.ts, 157, 40)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 157, 10)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 157, 10)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 157, 10)) - - if (typeof name === 'undefined') { ->name : Symbol(name, Decl(dependentReturnType1.ts, 157, 40)) - - return this.root.name; // Ok ->this.root.name : Symbol(name, Decl(dependentReturnType1.ts, 147, 12)) ->this.root : Symbol(Unnamed.root, Decl(dependentReturnType1.ts, 146, 15)) ->this : Symbol(Unnamed, Decl(dependentReturnType1.ts, 144, 1)) ->root : Symbol(Unnamed.root, Decl(dependentReturnType1.ts, 146, 15)) ->name : Symbol(name, Decl(dependentReturnType1.ts, 147, 12)) - } - this.root.name = name; ->this.root.name : Symbol(name, Decl(dependentReturnType1.ts, 147, 12)) ->this.root : Symbol(Unnamed.root, Decl(dependentReturnType1.ts, 146, 15)) ->this : Symbol(Unnamed, Decl(dependentReturnType1.ts, 144, 1)) ->root : Symbol(Unnamed.root, Decl(dependentReturnType1.ts, 146, 15)) ->name : Symbol(name, Decl(dependentReturnType1.ts, 147, 12)) ->name : Symbol(name, Decl(dependentReturnType1.ts, 157, 40)) - - return this; // Ok ->this : Symbol(Unnamed, Decl(dependentReturnType1.ts, 144, 1)) - } - - // Good conditional, wrong return expressions - name3<T extends string | undefined>(name?: T): T extends string ? this : T extends undefined ? string : never { ->name3 : Symbol(Unnamed.name3, Decl(dependentReturnType1.ts, 163, 5)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 166, 10)) ->name : Symbol(name, Decl(dependentReturnType1.ts, 166, 40)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 166, 10)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 166, 10)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 166, 10)) - - if (typeof name === 'undefined') { ->name : Symbol(name, Decl(dependentReturnType1.ts, 166, 40)) - - return this; // Error ->this : Symbol(Unnamed, Decl(dependentReturnType1.ts, 144, 1)) - } - this.root.name = name; ->this.root.name : Symbol(name, Decl(dependentReturnType1.ts, 147, 12)) ->this.root : Symbol(Unnamed.root, Decl(dependentReturnType1.ts, 146, 15)) ->this : Symbol(Unnamed, Decl(dependentReturnType1.ts, 144, 1)) ->root : Symbol(Unnamed.root, Decl(dependentReturnType1.ts, 146, 15)) ->name : Symbol(name, Decl(dependentReturnType1.ts, 147, 12)) ->name : Symbol(name, Decl(dependentReturnType1.ts, 166, 40)) - - return name; // Error ->name : Symbol(name, Decl(dependentReturnType1.ts, 166, 40)) - } -} - -// Conditional expressions -interface Aa { ->Aa : Symbol(Aa, Decl(dependentReturnType1.ts, 173, 1)) - - 1: number; ->1 : Symbol(Aa[1], Decl(dependentReturnType1.ts, 176, 14)) - - 2: string; ->2 : Symbol(Aa[2], Decl(dependentReturnType1.ts, 177, 14)) - - 3: boolean; ->3 : Symbol(Aa[3], Decl(dependentReturnType1.ts, 178, 14)) -} - -function trivialConditional<T extends 1 | 2 | 3>(x: T): Aa[T] { ->trivialConditional : Symbol(trivialConditional, Decl(dependentReturnType1.ts, 180, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 182, 28)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 182, 49)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 182, 28)) ->Aa : Symbol(Aa, Decl(dependentReturnType1.ts, 173, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 182, 28)) - - if (x !== 1) { ->x : Symbol(x, Decl(dependentReturnType1.ts, 182, 49)) - - return x === 2 ? "" : true; ->x : Symbol(x, Decl(dependentReturnType1.ts, 182, 49)) - } - else { - return 0; - } -} - -function conditional<T extends boolean>(x: T): ->conditional : Symbol(conditional, Decl(dependentReturnType1.ts, 189, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 191, 21)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 191, 40)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 191, 21)) - - T extends true ? 1 : T extends false ? 2 : never { ->T : Symbol(T, Decl(dependentReturnType1.ts, 191, 21)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 191, 21)) - - return x ? 1 : 2; // Ok ->x : Symbol(x, Decl(dependentReturnType1.ts, 191, 40)) -} - -function contextualConditional<T extends "a" | "b">( ->contextualConditional : Symbol(contextualConditional, Decl(dependentReturnType1.ts, 194, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 196, 31)) - - x: T ->x : Symbol(x, Decl(dependentReturnType1.ts, 196, 52)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 196, 31)) - -): T extends "a" ? "a" : T extends "b" ? number : never { ->T : Symbol(T, Decl(dependentReturnType1.ts, 196, 31)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 196, 31)) - - return x === "a" ? x : parseInt(x); // Ok ->x : Symbol(x, Decl(dependentReturnType1.ts, 196, 52)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 196, 52)) ->parseInt : Symbol(parseInt, Decl(lib.es5.d.ts, --, --)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 196, 52)) -} - -function conditionalWithError<T extends "a" | "b">( ->conditionalWithError : Symbol(conditionalWithError, Decl(dependentReturnType1.ts, 200, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 202, 30)) - - x: T ->x : Symbol(x, Decl(dependentReturnType1.ts, 202, 51)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 202, 30)) - -): T extends "a" ? number : T extends "b" ? string : never { ->T : Symbol(T, Decl(dependentReturnType1.ts, 202, 30)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 202, 30)) - - return x === "a" ? x : parseInt(x); // Error ->x : Symbol(x, Decl(dependentReturnType1.ts, 202, 51)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 202, 51)) ->parseInt : Symbol(parseInt, Decl(lib.es5.d.ts, --, --)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 202, 51)) -} - -// Multiple indexed type reductions -interface BB { ->BB : Symbol(BB, Decl(dependentReturnType1.ts, 206, 1)) - - "a": number; ->"a" : Symbol(BB["a"], Decl(dependentReturnType1.ts, 209, 14)) - - [y: number]: string; ->y : Symbol(y, Decl(dependentReturnType1.ts, 211, 5)) -} - -interface AA<T extends keyof BB> { ->AA : Symbol(AA, Decl(dependentReturnType1.ts, 212, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 214, 13)) ->BB : Symbol(BB, Decl(dependentReturnType1.ts, 206, 1)) - - "c": BB[T]; ->"c" : Symbol(AA["c"], Decl(dependentReturnType1.ts, 214, 34)) ->BB : Symbol(BB, Decl(dependentReturnType1.ts, 206, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 214, 13)) - - "d": boolean, ->"d" : Symbol(AA["d"], Decl(dependentReturnType1.ts, 215, 15)) -} - -function reduction<T extends keyof BB, U extends "c" | "d">(x: T, y: U): AA<T>[U] { ->reduction : Symbol(reduction, Decl(dependentReturnType1.ts, 217, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 219, 19)) ->BB : Symbol(BB, Decl(dependentReturnType1.ts, 206, 1)) ->U : Symbol(U, Decl(dependentReturnType1.ts, 219, 38)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 219, 60)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 219, 19)) ->y : Symbol(y, Decl(dependentReturnType1.ts, 219, 65)) ->U : Symbol(U, Decl(dependentReturnType1.ts, 219, 38)) ->AA : Symbol(AA, Decl(dependentReturnType1.ts, 212, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 219, 19)) ->U : Symbol(U, Decl(dependentReturnType1.ts, 219, 38)) - - if (y === "c" && x === "a") { ->y : Symbol(y, Decl(dependentReturnType1.ts, 219, 65)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 219, 60)) - - // AA<T>[U='c'] -> BB[T] - // BB[T='a'] -> number - return 0; // Ok - } - - return undefined as never; ->undefined : Symbol(undefined) -} - -// Substitution types are not narrowed -function subsCond<T extends 1 | 2 | 3>( ->subsCond : Symbol(subsCond, Decl(dependentReturnType1.ts, 227, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 230, 18)) - - x: T, ->x : Symbol(x, Decl(dependentReturnType1.ts, 230, 39)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 230, 18)) - -): T extends 1 | 2 ->T : Symbol(T, Decl(dependentReturnType1.ts, 230, 18)) - - ? T extends 1 ->T : Symbol(T, Decl(dependentReturnType1.ts, 230, 18)) - - ? string - : T extends 2 ->T : Symbol(T, Decl(dependentReturnType1.ts, 230, 18)) - - ? boolean - : never - : T extends 3 ->T : Symbol(T, Decl(dependentReturnType1.ts, 230, 18)) - - ? number - : never { - if (x === 1) { ->x : Symbol(x, Decl(dependentReturnType1.ts, 230, 39)) - - return ""; - } else if (x == 2) { ->x : Symbol(x, Decl(dependentReturnType1.ts, 230, 39)) - - return true; - } - return 3; -} - - -// Unsafe: check types overlap -declare function q(x: object): x is { b: number }; ->q : Symbol(q, Decl(dependentReturnType1.ts, 247, 1)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 251, 19)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 251, 19)) ->b : Symbol(b, Decl(dependentReturnType1.ts, 251, 37)) - -function foo<T extends { a: string } | { b: number }>( ->foo : Symbol(foo, Decl(dependentReturnType1.ts, 251, 50)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 252, 13)) ->a : Symbol(a, Decl(dependentReturnType1.ts, 252, 24)) ->b : Symbol(b, Decl(dependentReturnType1.ts, 252, 40)) - - x: T, ->x : Symbol(x, Decl(dependentReturnType1.ts, 252, 54)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 252, 13)) - -): T extends { a: string } ? number : T extends { b: number } ? string : never { ->T : Symbol(T, Decl(dependentReturnType1.ts, 252, 13)) ->a : Symbol(a, Decl(dependentReturnType1.ts, 254, 14)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 252, 13)) ->b : Symbol(b, Decl(dependentReturnType1.ts, 254, 49)) - - if (q(x)) { ->q : Symbol(q, Decl(dependentReturnType1.ts, 247, 1)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 252, 54)) - - x.b; ->x.b : Symbol(b, Decl(dependentReturnType1.ts, 252, 40)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 252, 54)) ->b : Symbol(b, Decl(dependentReturnType1.ts, 252, 40)) - - return ""; - } - x.a; ->x.a : Symbol(a, Decl(dependentReturnType1.ts, 252, 24)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 252, 54)) ->a : Symbol(a, Decl(dependentReturnType1.ts, 252, 24)) - - return 1; -} - -let y = { a: "", b: 1 } ->y : Symbol(y, Decl(dependentReturnType1.ts, 263, 3)) ->a : Symbol(a, Decl(dependentReturnType1.ts, 263, 9)) ->b : Symbol(b, Decl(dependentReturnType1.ts, 263, 16)) - -const r = foo<{ a: string }>(y); // type says number but actually string ->r : Symbol(r, Decl(dependentReturnType1.ts, 264, 5)) ->foo : Symbol(foo, Decl(dependentReturnType1.ts, 251, 50)) ->a : Symbol(a, Decl(dependentReturnType1.ts, 264, 15)) ->y : Symbol(y, Decl(dependentReturnType1.ts, 263, 3)) - -type HelperCond<T, A, R1, B, R2> = T extends A ? R1 : T extends B ? R2 : never; ->HelperCond : Symbol(HelperCond, Decl(dependentReturnType1.ts, 264, 32)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 266, 16)) ->A : Symbol(A, Decl(dependentReturnType1.ts, 266, 18)) ->R1 : Symbol(R1, Decl(dependentReturnType1.ts, 266, 21)) ->B : Symbol(B, Decl(dependentReturnType1.ts, 266, 25)) ->R2 : Symbol(R2, Decl(dependentReturnType1.ts, 266, 28)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 266, 16)) ->A : Symbol(A, Decl(dependentReturnType1.ts, 266, 18)) ->R1 : Symbol(R1, Decl(dependentReturnType1.ts, 266, 21)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 266, 16)) ->B : Symbol(B, Decl(dependentReturnType1.ts, 266, 25)) ->R2 : Symbol(R2, Decl(dependentReturnType1.ts, 266, 28)) - -// We don't narrow the return type because the conditionals are not distributive -function foo2<U extends string | number, V extends boolean>(x: U, y: V): ->foo2 : Symbol(foo2, Decl(dependentReturnType1.ts, 266, 79)) ->U : Symbol(U, Decl(dependentReturnType1.ts, 269, 14)) ->V : Symbol(V, Decl(dependentReturnType1.ts, 269, 40)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 269, 60)) ->U : Symbol(U, Decl(dependentReturnType1.ts, 269, 14)) ->y : Symbol(y, Decl(dependentReturnType1.ts, 269, 65)) ->V : Symbol(V, Decl(dependentReturnType1.ts, 269, 40)) - - HelperCond<{ x: U, y: V }, ->HelperCond : Symbol(HelperCond, Decl(dependentReturnType1.ts, 264, 32)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 270, 16)) ->U : Symbol(U, Decl(dependentReturnType1.ts, 269, 14)) ->y : Symbol(y, Decl(dependentReturnType1.ts, 270, 22)) ->V : Symbol(V, Decl(dependentReturnType1.ts, 269, 40)) - - { x: string, y: true }, 1, ->x : Symbol(x, Decl(dependentReturnType1.ts, 271, 9)) ->y : Symbol(y, Decl(dependentReturnType1.ts, 271, 20)) - - { x: number, y: false }, 2> { ->x : Symbol(x, Decl(dependentReturnType1.ts, 272, 9)) ->y : Symbol(y, Decl(dependentReturnType1.ts, 272, 20)) - - if (typeof x === "string" && y === true) { ->x : Symbol(x, Decl(dependentReturnType1.ts, 269, 60)) ->y : Symbol(y, Decl(dependentReturnType1.ts, 269, 65)) - - return 1; // Error - } - if (typeof x === "number" && y === false) { ->x : Symbol(x, Decl(dependentReturnType1.ts, 269, 60)) ->y : Symbol(y, Decl(dependentReturnType1.ts, 269, 65)) - - return 2; // Error - } - return 0; // Error -} - -// From https://github.com/microsoft/TypeScript/issues/24929#issue-332087943 -declare function isString(s: unknown): s is string; ->isString : Symbol(isString, Decl(dependentReturnType1.ts, 280, 1)) ->s : Symbol(s, Decl(dependentReturnType1.ts, 283, 26)) ->s : Symbol(s, Decl(dependentReturnType1.ts, 283, 26)) - -// capitalize a string or each element of an array of strings -function capitalize<T extends string | string[]>( ->capitalize : Symbol(capitalize, Decl(dependentReturnType1.ts, 283, 51)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 285, 20)) - - input: T ->input : Symbol(input, Decl(dependentReturnType1.ts, 285, 49)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 285, 20)) - -): T extends string[] ? string[] : T extends string ? string : never { ->T : Symbol(T, Decl(dependentReturnType1.ts, 285, 20)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 285, 20)) - - if (isString(input)) { ->isString : Symbol(isString, Decl(dependentReturnType1.ts, 280, 1)) ->input : Symbol(input, Decl(dependentReturnType1.ts, 285, 49)) - - return input[0].toUpperCase() + input.slice(1); // Ok ->input[0].toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) ->input : Symbol(input, Decl(dependentReturnType1.ts, 285, 49)) ->toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) ->input.slice : Symbol(String.slice, Decl(lib.es5.d.ts, --, --)) ->input : Symbol(input, Decl(dependentReturnType1.ts, 285, 49)) ->slice : Symbol(String.slice, Decl(lib.es5.d.ts, --, --)) - - } else { - return input.map(elt => capitalize(elt)); // Ok ->input.map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --)) ->input : Symbol(input, Decl(dependentReturnType1.ts, 285, 49)) ->map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --)) ->elt : Symbol(elt, Decl(dependentReturnType1.ts, 291, 25)) ->capitalize : Symbol(capitalize, Decl(dependentReturnType1.ts, 283, 51)) ->elt : Symbol(elt, Decl(dependentReturnType1.ts, 291, 25)) - } -} - -function badCapitalize<T extends string | string[]>( ->badCapitalize : Symbol(badCapitalize, Decl(dependentReturnType1.ts, 293, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 295, 23)) - - input: T ->input : Symbol(input, Decl(dependentReturnType1.ts, 295, 52)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 295, 23)) - -): T extends string[] ? string[] : T extends string ? string : never { ->T : Symbol(T, Decl(dependentReturnType1.ts, 295, 23)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 295, 23)) - - if (isString(input)) { ->isString : Symbol(isString, Decl(dependentReturnType1.ts, 280, 1)) ->input : Symbol(input, Decl(dependentReturnType1.ts, 295, 52)) - - return input[0].toUpperCase() + input.slice(1); // Ok ->input[0].toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) ->input : Symbol(input, Decl(dependentReturnType1.ts, 295, 52)) ->toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) ->input.slice : Symbol(String.slice, Decl(lib.es5.d.ts, --, --)) ->input : Symbol(input, Decl(dependentReturnType1.ts, 295, 52)) ->slice : Symbol(String.slice, Decl(lib.es5.d.ts, --, --)) - - } else { - return input[0].toUpperCase() + input.slice(1); // Bad, error ->input[0].toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) ->input : Symbol(input, Decl(dependentReturnType1.ts, 295, 52)) ->toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) ->input.slice : Symbol(Array.slice, Decl(lib.es5.d.ts, --, --)) ->input : Symbol(input, Decl(dependentReturnType1.ts, 295, 52)) ->slice : Symbol(Array.slice, Decl(lib.es5.d.ts, --, --)) - } -} - -// No narrowing because conditional's extends type is different from type parameter constraint types -function voidRet<T extends { a: string } | undefined>( ->voidRet : Symbol(voidRet, Decl(dependentReturnType1.ts, 303, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 306, 17)) ->a : Symbol(a, Decl(dependentReturnType1.ts, 306, 28)) - - x: T ->x : Symbol(x, Decl(dependentReturnType1.ts, 306, 54)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 306, 17)) - -): T extends {} ? void : T extends undefined ? number : never { ->T : Symbol(T, Decl(dependentReturnType1.ts, 306, 17)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 306, 17)) - - if (x) { ->x : Symbol(x, Decl(dependentReturnType1.ts, 306, 54)) - - return; - } - return 1; -} - -// Multiple type parameters at once -function woo<T extends string | number, U extends string | number>( ->woo : Symbol(woo, Decl(dependentReturnType1.ts, 313, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 316, 13)) ->U : Symbol(U, Decl(dependentReturnType1.ts, 316, 39)) - - x: T, ->x : Symbol(x, Decl(dependentReturnType1.ts, 316, 67)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 316, 13)) - - y: U, ->y : Symbol(y, Decl(dependentReturnType1.ts, 317, 9)) ->U : Symbol(U, Decl(dependentReturnType1.ts, 316, 39)) - -): T extends string ->T : Symbol(T, Decl(dependentReturnType1.ts, 316, 13)) - - ? U extends string ->U : Symbol(U, Decl(dependentReturnType1.ts, 316, 39)) - - ? 1 - : U extends number ->U : Symbol(U, Decl(dependentReturnType1.ts, 316, 39)) - - ? 2 - : never - : T extends number ->T : Symbol(T, Decl(dependentReturnType1.ts, 316, 13)) - - ? U extends number ->U : Symbol(U, Decl(dependentReturnType1.ts, 316, 39)) - - ? 3 - : U extends string ->U : Symbol(U, Decl(dependentReturnType1.ts, 316, 39)) - - ? 4 - : never - : never { - if (typeof x === "number" && typeof y === "string") { ->x : Symbol(x, Decl(dependentReturnType1.ts, 316, 67)) ->y : Symbol(y, Decl(dependentReturnType1.ts, 317, 9)) - - return 1; // Good error - } - return undefined as any; ->undefined : Symbol(undefined) -} - -function ttt<T extends string | number, U extends string | number>( ->ttt : Symbol(ttt, Decl(dependentReturnType1.ts, 336, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 338, 13)) ->U : Symbol(U, Decl(dependentReturnType1.ts, 338, 39)) - - x: T, ->x : Symbol(x, Decl(dependentReturnType1.ts, 338, 67)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 338, 13)) - - y: U, ->y : Symbol(y, Decl(dependentReturnType1.ts, 339, 9)) ->U : Symbol(U, Decl(dependentReturnType1.ts, 338, 39)) - -): T extends string ->T : Symbol(T, Decl(dependentReturnType1.ts, 338, 13)) - - ? U extends string ->U : Symbol(U, Decl(dependentReturnType1.ts, 338, 39)) - - ? 1 - : U extends number ->U : Symbol(U, Decl(dependentReturnType1.ts, 338, 39)) - - ? 2 - : never - : T extends number ->T : Symbol(T, Decl(dependentReturnType1.ts, 338, 13)) - - ? U extends number ->U : Symbol(U, Decl(dependentReturnType1.ts, 338, 39)) - - ? 3 - : U extends string ->U : Symbol(U, Decl(dependentReturnType1.ts, 338, 39)) - - ? 4 - : never - : never { - if (typeof x === "number" && typeof y === "string") { ->x : Symbol(x, Decl(dependentReturnType1.ts, 338, 67)) ->y : Symbol(y, Decl(dependentReturnType1.ts, 339, 9)) - - return 4; // Ok - } - - return undefined as any; ->undefined : Symbol(undefined) -} - -// Shadowing of the narrowed reference -function shadowing<T extends 1 | 2>(x: T): T extends 1 ? number : T extends 2 ? string : never { ->shadowing : Symbol(shadowing, Decl(dependentReturnType1.ts, 359, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 362, 19)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 362, 36)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 362, 19)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 362, 19)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 362, 19)) - - if (true) { - let x: number = Math.random() ? 1 : 2; ->x : Symbol(x, Decl(dependentReturnType1.ts, 364, 11)) ->Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) ->Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.esnext.float16.d.ts, --, --)) ->random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) - - if (x === 1) { ->x : Symbol(x, Decl(dependentReturnType1.ts, 364, 11)) - - return 1; // Error - } - return ""; // Error - } -} - -function noShadowing<T extends 1 | 2>(x: T): T extends 1 ? number : T extends 2 ? string : never { ->noShadowing : Symbol(noShadowing, Decl(dependentReturnType1.ts, 370, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 372, 21)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 372, 38)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 372, 21)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 372, 21)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 372, 21)) - - if (true) { - if (x === 1) { ->x : Symbol(x, Decl(dependentReturnType1.ts, 372, 38)) - - return 1; // Ok - } - return ""; // Ok - } -} - -// If the narrowing reference is out of scope, we simply won't narrow its type -declare let someX: boolean; ->someX : Symbol(someX, Decl(dependentReturnType1.ts, 382, 11)) - -function scope2<T extends boolean>(a: T): T extends true ? 1 : T extends false ? 2 : never { ->scope2 : Symbol(scope2, Decl(dependentReturnType1.ts, 382, 27)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 383, 16)) ->a : Symbol(a, Decl(dependentReturnType1.ts, 383, 35)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 383, 16)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 383, 16)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 383, 16)) - - if ((true)) { - const someX = a; ->someX : Symbol(someX, Decl(dependentReturnType1.ts, 385, 13)) ->a : Symbol(a, Decl(dependentReturnType1.ts, 383, 35)) - - if (someX) { // We narrow `someX` and the return type here ->someX : Symbol(someX, Decl(dependentReturnType1.ts, 385, 13)) - - return 1; - } - } - if (!someX) { // This is a different `someX`, so we don't narrow here ->someX : Symbol(someX, Decl(dependentReturnType1.ts, 382, 11)) - - return 2; - } - - return undefined as any; ->undefined : Symbol(undefined) -} - -function moreShadowing<T extends 1 | 2>(x: T): T extends 1 ? number : T extends 2 ? string : never { ->moreShadowing : Symbol(moreShadowing, Decl(dependentReturnType1.ts, 395, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 397, 23)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 397, 40)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 397, 23)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 397, 23)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 397, 23)) - - if (x === 2) { ->x : Symbol(x, Decl(dependentReturnType1.ts, 397, 40)) - - let x: number = Math.random() ? 1 : 2; ->x : Symbol(x, Decl(dependentReturnType1.ts, 399, 11)) ->Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) ->Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.esnext.float16.d.ts, --, --)) ->random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) - - if (x === 1) { ->x : Symbol(x, Decl(dependentReturnType1.ts, 399, 11)) - - return 1; // Error - } - return ""; // Ok - } - return 0; // Ok -} - -// This would be unsafe to narrow due to `infer` type. -function withInfer<T extends [string] | number>(x: T): T extends [infer R] ? R : T extends number ? boolean : never { ->withInfer : Symbol(withInfer, Decl(dependentReturnType1.ts, 406, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 409, 19)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 409, 48)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 409, 19)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 409, 19)) ->R : Symbol(R, Decl(dependentReturnType1.ts, 409, 71)) ->R : Symbol(R, Decl(dependentReturnType1.ts, 409, 71)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 409, 19)) - - if (typeof x === "number") { ->x : Symbol(x, Decl(dependentReturnType1.ts, 409, 48)) - - return true; - } - return ""; -} - -const withInferResult = withInfer(["a"] as const); // The type says it returns `"a"`, but the function actually returns `""`. ->withInferResult : Symbol(withInferResult, Decl(dependentReturnType1.ts, 416, 5)) ->withInfer : Symbol(withInfer, Decl(dependentReturnType1.ts, 406, 1)) ->const : Symbol(const) - -// Ok -async function abool<T extends true | false>(x: T): Promise<T extends true ? 1 : T extends false ? 2 : never> { ->abool : Symbol(abool, Decl(dependentReturnType1.ts, 416, 50)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 419, 21)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 419, 45)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 419, 21)) ->Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 419, 21)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 419, 21)) - - if (x) { ->x : Symbol(x, Decl(dependentReturnType1.ts, 419, 45)) - - return 1; - } - return 2; -} - -// Ok -function* bbool<T extends true | false>(x: T): Generator<number, T extends true ? 1 : T extends false ? 2 : never, unknown> { ->bbool : Symbol(bbool, Decl(dependentReturnType1.ts, 424, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 427, 16)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 427, 40)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 427, 16)) ->Generator : Symbol(Generator, Decl(lib.es2015.generator.d.ts, --, --)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 427, 16)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 427, 16)) - - yield 3; - if (x) { ->x : Symbol(x, Decl(dependentReturnType1.ts, 427, 40)) - - return 1; - } - return 2; -} - -// We don't do the same type of narrowing for `yield` statements -function* cbool<T extends true | false>(x: T): Generator<T extends true ? 1 : T extends false ? 2 : never, number, unknown> { ->cbool : Symbol(cbool, Decl(dependentReturnType1.ts, 433, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 436, 16)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 436, 40)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 436, 16)) ->Generator : Symbol(Generator, Decl(lib.es2015.generator.d.ts, --, --)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 436, 16)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 436, 16)) - - if (x) { ->x : Symbol(x, Decl(dependentReturnType1.ts, 436, 40)) - - yield 1; - } - yield 2; - return 0; -} - -// From #33912 -abstract class Operation<T, R> { ->Operation : Symbol(Operation, Decl(dependentReturnType1.ts, 442, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 445, 25)) ->R : Symbol(R, Decl(dependentReturnType1.ts, 445, 27)) - - abstract perform(t: T): R; ->perform : Symbol(Operation.perform, Decl(dependentReturnType1.ts, 445, 32)) ->t : Symbol(t, Decl(dependentReturnType1.ts, 446, 21)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 445, 25)) ->R : Symbol(R, Decl(dependentReturnType1.ts, 445, 27)) -} - -type ConditionalReturnType<T, R, EOp extends Operation<T, R> | undefined> = ->ConditionalReturnType : Symbol(ConditionalReturnType, Decl(dependentReturnType1.ts, 447, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 449, 27)) ->R : Symbol(R, Decl(dependentReturnType1.ts, 449, 29)) ->EOp : Symbol(EOp, Decl(dependentReturnType1.ts, 449, 32)) ->Operation : Symbol(Operation, Decl(dependentReturnType1.ts, 442, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 449, 27)) ->R : Symbol(R, Decl(dependentReturnType1.ts, 449, 29)) - - EOp extends Operation<T, R> ? R : EOp extends undefined ? T | R : never; ->EOp : Symbol(EOp, Decl(dependentReturnType1.ts, 449, 32)) ->Operation : Symbol(Operation, Decl(dependentReturnType1.ts, 442, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 449, 27)) ->R : Symbol(R, Decl(dependentReturnType1.ts, 449, 29)) ->R : Symbol(R, Decl(dependentReturnType1.ts, 449, 29)) ->EOp : Symbol(EOp, Decl(dependentReturnType1.ts, 449, 32)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 449, 27)) ->R : Symbol(R, Decl(dependentReturnType1.ts, 449, 29)) - - -class ConditionalOperation< ->ConditionalOperation : Symbol(ConditionalOperation, Decl(dependentReturnType1.ts, 450, 76)) - - T, ->T : Symbol(T, Decl(dependentReturnType1.ts, 453, 27)) - - R, ->R : Symbol(R, Decl(dependentReturnType1.ts, 454, 6)) - - EOp extends Operation<T, R> | undefined, ->EOp : Symbol(EOp, Decl(dependentReturnType1.ts, 455, 6)) ->Operation : Symbol(Operation, Decl(dependentReturnType1.ts, 442, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 453, 27)) ->R : Symbol(R, Decl(dependentReturnType1.ts, 454, 6)) - -> extends Operation<T, ConditionalReturnType<T, R, EOp>> { ->Operation : Symbol(Operation, Decl(dependentReturnType1.ts, 442, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 453, 27)) ->ConditionalReturnType : Symbol(ConditionalReturnType, Decl(dependentReturnType1.ts, 447, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 453, 27)) ->R : Symbol(R, Decl(dependentReturnType1.ts, 454, 6)) ->EOp : Symbol(EOp, Decl(dependentReturnType1.ts, 455, 6)) - - constructor( - private predicate: (value: T) => boolean, ->predicate : Symbol(ConditionalOperation.predicate, Decl(dependentReturnType1.ts, 458, 16)) ->value : Symbol(value, Decl(dependentReturnType1.ts, 459, 28)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 453, 27)) - - private thenOp: Operation<T, R>, ->thenOp : Symbol(ConditionalOperation.thenOp, Decl(dependentReturnType1.ts, 459, 49)) ->Operation : Symbol(Operation, Decl(dependentReturnType1.ts, 442, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 453, 27)) ->R : Symbol(R, Decl(dependentReturnType1.ts, 454, 6)) - - private elseOp?: EOp, ->elseOp : Symbol(ConditionalOperation.elseOp, Decl(dependentReturnType1.ts, 460, 40)) ->EOp : Symbol(EOp, Decl(dependentReturnType1.ts, 455, 6)) - - ) { - super(); ->super : Symbol(Operation, Decl(dependentReturnType1.ts, 442, 1)) - } - - // We won't try to narrow the return type because `T` is declared on the class and we don't analyze this case. - perform(t: T): ConditionalReturnType<T, R, EOp> { ->perform : Symbol(ConditionalOperation.perform, Decl(dependentReturnType1.ts, 464, 5)) ->t : Symbol(t, Decl(dependentReturnType1.ts, 467, 12)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 453, 27)) ->ConditionalReturnType : Symbol(ConditionalReturnType, Decl(dependentReturnType1.ts, 447, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 453, 27)) ->R : Symbol(R, Decl(dependentReturnType1.ts, 454, 6)) ->EOp : Symbol(EOp, Decl(dependentReturnType1.ts, 455, 6)) - - if (this.predicate(t)) { ->this.predicate : Symbol(ConditionalOperation.predicate, Decl(dependentReturnType1.ts, 458, 16)) ->this : Symbol(ConditionalOperation, Decl(dependentReturnType1.ts, 450, 76)) ->predicate : Symbol(ConditionalOperation.predicate, Decl(dependentReturnType1.ts, 458, 16)) ->t : Symbol(t, Decl(dependentReturnType1.ts, 467, 12)) - - return this.thenOp.perform(t); // Bad: this is assignable to all of the branches of the conditional, but we still can't return it ->this.thenOp.perform : Symbol(Operation.perform, Decl(dependentReturnType1.ts, 445, 32)) ->this.thenOp : Symbol(ConditionalOperation.thenOp, Decl(dependentReturnType1.ts, 459, 49)) ->this : Symbol(ConditionalOperation, Decl(dependentReturnType1.ts, 450, 76)) ->thenOp : Symbol(ConditionalOperation.thenOp, Decl(dependentReturnType1.ts, 459, 49)) ->perform : Symbol(Operation.perform, Decl(dependentReturnType1.ts, 445, 32)) ->t : Symbol(t, Decl(dependentReturnType1.ts, 467, 12)) - - } else if (typeof this.elseOp !== "undefined") { ->this.elseOp : Symbol(ConditionalOperation.elseOp, Decl(dependentReturnType1.ts, 460, 40)) ->this : Symbol(ConditionalOperation, Decl(dependentReturnType1.ts, 450, 76)) ->elseOp : Symbol(ConditionalOperation.elseOp, Decl(dependentReturnType1.ts, 460, 40)) - - return this.elseOp.perform(t); // Would be ok ->this.elseOp.perform : Symbol(Operation.perform, Decl(dependentReturnType1.ts, 445, 32)) ->this.elseOp : Symbol(ConditionalOperation.elseOp, Decl(dependentReturnType1.ts, 460, 40)) ->this : Symbol(ConditionalOperation, Decl(dependentReturnType1.ts, 450, 76)) ->elseOp : Symbol(ConditionalOperation.elseOp, Decl(dependentReturnType1.ts, 460, 40)) ->perform : Symbol(Operation.perform, Decl(dependentReturnType1.ts, 445, 32)) ->t : Symbol(t, Decl(dependentReturnType1.ts, 467, 12)) - - } else { - return t; // Would be ok ->t : Symbol(t, Decl(dependentReturnType1.ts, 467, 12)) - } - } -} - -// Like the version above, we will not attempt to narrow because there's more than one reference to `T`, -// because `T` shows up in the type of `predicate`. -function perform<T, R, EOp extends Operation<T, R> | undefined>( ->perform : Symbol(perform, Decl(dependentReturnType1.ts, 476, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 480, 17)) ->R : Symbol(R, Decl(dependentReturnType1.ts, 480, 19)) ->EOp : Symbol(EOp, Decl(dependentReturnType1.ts, 480, 22)) ->Operation : Symbol(Operation, Decl(dependentReturnType1.ts, 442, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 480, 17)) ->R : Symbol(R, Decl(dependentReturnType1.ts, 480, 19)) - - t: T, ->t : Symbol(t, Decl(dependentReturnType1.ts, 480, 64)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 480, 17)) - - predicate: (value: T) => boolean, ->predicate : Symbol(predicate, Decl(dependentReturnType1.ts, 481, 9)) ->value : Symbol(value, Decl(dependentReturnType1.ts, 482, 16)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 480, 17)) - - thenOp: Operation<T, R>, ->thenOp : Symbol(thenOp, Decl(dependentReturnType1.ts, 482, 37)) ->Operation : Symbol(Operation, Decl(dependentReturnType1.ts, 442, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 480, 17)) ->R : Symbol(R, Decl(dependentReturnType1.ts, 480, 19)) - - elseOp?: EOp, ->elseOp : Symbol(elseOp, Decl(dependentReturnType1.ts, 483, 28)) ->EOp : Symbol(EOp, Decl(dependentReturnType1.ts, 480, 22)) - - ): ConditionalReturnType<T, R, EOp> { ->ConditionalReturnType : Symbol(ConditionalReturnType, Decl(dependentReturnType1.ts, 447, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 480, 17)) ->R : Symbol(R, Decl(dependentReturnType1.ts, 480, 19)) ->EOp : Symbol(EOp, Decl(dependentReturnType1.ts, 480, 22)) - - if (predicate(t)) { ->predicate : Symbol(predicate, Decl(dependentReturnType1.ts, 481, 9)) ->t : Symbol(t, Decl(dependentReturnType1.ts, 480, 64)) - - return thenOp.perform(t); // Bad: this is assignable to all of the branches of the conditional, but we still can't return it ->thenOp.perform : Symbol(Operation.perform, Decl(dependentReturnType1.ts, 445, 32)) ->thenOp : Symbol(thenOp, Decl(dependentReturnType1.ts, 482, 37)) ->perform : Symbol(Operation.perform, Decl(dependentReturnType1.ts, 445, 32)) ->t : Symbol(t, Decl(dependentReturnType1.ts, 480, 64)) - - } else if (elseOp !== undefined) { ->elseOp : Symbol(elseOp, Decl(dependentReturnType1.ts, 483, 28)) ->undefined : Symbol(undefined) - - return elseOp.perform(t); // Would be ok ->elseOp.perform : Symbol(Operation.perform, Decl(dependentReturnType1.ts, 445, 32)) ->elseOp : Symbol(elseOp, Decl(dependentReturnType1.ts, 483, 28)) ->perform : Symbol(Operation.perform, Decl(dependentReturnType1.ts, 445, 32)) ->t : Symbol(t, Decl(dependentReturnType1.ts, 480, 64)) - - } else { - return t; // Would be ok ->t : Symbol(t, Decl(dependentReturnType1.ts, 480, 64)) - } -} - -// Return conditional expressions with parentheses -function returnStuff1<T extends boolean>(x: T ): T extends true ? 1 : T extends false ? 2 : never { ->returnStuff1 : Symbol(returnStuff1, Decl(dependentReturnType1.ts, 493, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 496, 22)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 496, 41)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 496, 22)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 496, 22)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 496, 22)) - - return (x ? (1) : 2); ->x : Symbol(x, Decl(dependentReturnType1.ts, 496, 41)) -} - -function returnStuff2<T extends 1 | 2 | "a">(x: T ): ->returnStuff2 : Symbol(returnStuff2, Decl(dependentReturnType1.ts, 498, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 500, 22)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 500, 45)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 500, 22)) - - T extends 1 ? "one" : T extends 2 ? "two" : T extends "a" ? 0 : never { ->T : Symbol(T, Decl(dependentReturnType1.ts, 500, 22)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 500, 22)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 500, 22)) - - return (typeof x === "string" ? 0 : (x === 1 ? ("one") : "two")); ->x : Symbol(x, Decl(dependentReturnType1.ts, 500, 45)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 500, 45)) -} - -// If the conditional type's input is `never`, then it resolves to `never`: -function neverOk<T extends boolean>(x: T): T extends true ? 1 : T extends false ? 2 : never { ->neverOk : Symbol(neverOk, Decl(dependentReturnType1.ts, 503, 1)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 506, 17)) ->x : Symbol(x, Decl(dependentReturnType1.ts, 506, 36)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 506, 17)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 506, 17)) ->T : Symbol(T, Decl(dependentReturnType1.ts, 506, 17)) - - if (x === true) { ->x : Symbol(x, Decl(dependentReturnType1.ts, 506, 36)) - - return 1; - } - if (x === false) { ->x : Symbol(x, Decl(dependentReturnType1.ts, 506, 36)) - - return 2; - } - return 1; -} diff --git a/tests/baselines/reference/dependentReturnType1.types b/tests/baselines/reference/dependentReturnType1.types deleted file mode 100644 index 96265db6b57be..0000000000000 --- a/tests/baselines/reference/dependentReturnType1.types +++ /dev/null @@ -1,2008 +0,0 @@ -//// [tests/cases/compiler/dependentReturnType1.ts] //// - -=== dependentReturnType1.ts === -interface A { - 1: number; ->1 : number -> : ^^^^^^ - - 2: string; ->2 : string -> : ^^^^^^ -} - -function f1<T extends 1 | 2>(x: T): A[T] { ->f1 : <T extends 1 | 2>(x: T) => A[T] -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->x : T -> : ^ - - if (x === 1) { ->x === 1 : boolean -> : ^^^^^^^ ->x : T -> : ^ ->1 : 1 -> : ^ - - return 0; // Ok ->0 : 0 -> : ^ - } - else { - return 1; // Error ->1 : 1 -> : ^ - } -} - -interface C { - 1: number; ->1 : number -> : ^^^^^^ - - 2: string; ->2 : string -> : ^^^^^^ - - 3: boolean; ->3 : boolean -> : ^^^^^^^ -} - -function f2<T extends 1 | 2 | 3>(x: T): C[T] { ->f2 : <T extends 1 | 2 | 3>(x: T) => C[T] -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->x : T -> : ^ - - if (x === 1) { ->x === 1 : boolean -> : ^^^^^^^ ->x : T -> : ^ ->1 : 1 -> : ^ - - return 0; // Ok ->0 : 0 -> : ^ - } - else { - return ""; // Error, returned expression needs to have type string & boolean (= never) ->"" : "" -> : ^^ - } -} - -function f3<T extends 1 | 2 | 3>(x: T): T extends 1 ? number : T extends 2 ? string : T extends 3 ? boolean : never { ->f3 : <T extends 1 | 2 | 3>(x: T) => T extends 1 ? number : T extends 2 ? string : T extends 3 ? boolean : never -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->x : T -> : ^ - - if (x === 1) { ->x === 1 : boolean -> : ^^^^^^^ ->x : T -> : ^ ->1 : 1 -> : ^ - - return 0; // Ok ->0 : 0 -> : ^ - } - else { - return ""; // Error, returned expression needs to have type string & boolean (= never) ->"" : "" -> : ^^ - } -} - -interface One { - a: "a"; ->a : "a" -> : ^^^ - - b: "b"; ->b : "b" -> : ^^^ - - c: "c"; ->c : "c" -> : ^^^ - - d: "d"; ->d : "d" -> : ^^^ -} - -interface Two { - a: "a"; ->a : "a" -> : ^^^ - - b: "b"; ->b : "b" -> : ^^^ - - e: "e"; ->e : "e" -> : ^^^ - - f: "f"; ->f : "f" -> : ^^^ -} - -interface Three { - a: "a"; ->a : "a" -> : ^^^ - - c: "c"; ->c : "c" -> : ^^^ - - e: "e"; ->e : "e" -> : ^^^ - - g: "g"; ->g : "g" -> : ^^^ -} - -interface Four { - a: "a"; ->a : "a" -> : ^^^ - - d: "d"; ->d : "d" -> : ^^^ - - f: "f"; ->f : "f" -> : ^^^ - - g: "g"; ->g : "g" -> : ^^^ -} -// Badly written conditional return type, will not trigger narrowing -function f10<T extends 1 | 2 | 3 | 4>(x: T): T extends 1 ? One : T extends 2 ? Two : T extends 3 ? Three : Four { ->f10 : <T extends 1 | 2 | 3 | 4>(x: T) => T extends 1 ? One : T extends 2 ? Two : T extends 3 ? Three : Four -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->x : T -> : ^ - - if (x === 1 || x === 2) { ->x === 1 || x === 2 : boolean -> : ^^^^^^^ ->x === 1 : boolean -> : ^^^^^^^ ->x : T -> : ^ ->1 : 1 -> : ^ ->x === 2 : boolean -> : ^^^^^^^ ->x : T -> : ^ ->2 : 2 -> : ^ - - return { a: "a", b: "b", c: "c", d: "d", e: "e", f: "f" }; // Error ->{ a: "a", b: "b", c: "c", d: "d", e: "e", f: "f" } : { a: "a"; b: "b"; c: "c"; d: "d"; e: "e"; f: "f"; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->a : "a" -> : ^^^ ->"a" : "a" -> : ^^^ ->b : "b" -> : ^^^ ->"b" : "b" -> : ^^^ ->c : "c" -> : ^^^ ->"c" : "c" -> : ^^^ ->d : "d" -> : ^^^ ->"d" : "d" -> : ^^^ ->e : "e" -> : ^^^ ->"e" : "e" -> : ^^^ ->f : "f" -> : ^^^ ->"f" : "f" -> : ^^^ - } - return { a: "a", b: "b", c: "c", d: "d", e: "e", f: "f", g: "g" }; // Error ->{ a: "a", b: "b", c: "c", d: "d", e: "e", f: "f", g: "g" } : { a: "a"; b: "b"; c: "c"; d: "d"; e: "e"; f: "f"; g: "g"; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->a : "a" -> : ^^^ ->"a" : "a" -> : ^^^ ->b : "b" -> : ^^^ ->"b" : "b" -> : ^^^ ->c : "c" -> : ^^^ ->"c" : "c" -> : ^^^ ->d : "d" -> : ^^^ ->"d" : "d" -> : ^^^ ->e : "e" -> : ^^^ ->"e" : "e" -> : ^^^ ->f : "f" -> : ^^^ ->"f" : "f" -> : ^^^ ->g : "g" -> : ^^^ ->"g" : "g" -> : ^^^ -} -// Well written conditional -function f101<T extends 1 | 2 | 3 | 4>(x: T): T extends 1 ? One : T extends 2 ? Two : T extends 3 ? Three : T extends 4 ? Four : never { ->f101 : <T extends 1 | 2 | 3 | 4>(x: T) => T extends 1 ? One : T extends 2 ? Two : T extends 3 ? Three : T extends 4 ? Four : never -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->x : T -> : ^ - - if (x === 1 || x === 2) { ->x === 1 || x === 2 : boolean -> : ^^^^^^^ ->x === 1 : boolean -> : ^^^^^^^ ->x : T -> : ^ ->1 : 1 -> : ^ ->x === 2 : boolean -> : ^^^^^^^ ->x : T -> : ^ ->2 : 2 -> : ^ - - return { a: "a", b: "b", c: "c", d: "d", e: "e", f: "f" }; // Ok ->{ a: "a", b: "b", c: "c", d: "d", e: "e", f: "f" } : { a: "a"; b: "b"; c: "c"; d: "d"; e: "e"; f: "f"; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->a : "a" -> : ^^^ ->"a" : "a" -> : ^^^ ->b : "b" -> : ^^^ ->"b" : "b" -> : ^^^ ->c : "c" -> : ^^^ ->"c" : "c" -> : ^^^ ->d : "d" -> : ^^^ ->"d" : "d" -> : ^^^ ->e : "e" -> : ^^^ ->"e" : "e" -> : ^^^ ->f : "f" -> : ^^^ ->"f" : "f" -> : ^^^ - } - // Excess property becomes a problem with the change, - // because we now check assignability to a narrower type... - return { a: "a", b: "b", c: "c", d: "d", e: "e", f: "f", g: "g" }; // EPC Error ->{ a: "a", b: "b", c: "c", d: "d", e: "e", f: "f", g: "g" } : { a: "a"; b: string; c: "c"; d: "d"; e: "e"; f: "f"; g: "g"; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->a : "a" -> : ^^^ ->"a" : "a" -> : ^^^ ->b : string -> : ^^^^^^ ->"b" : "b" -> : ^^^ ->c : "c" -> : ^^^ ->"c" : "c" -> : ^^^ ->d : "d" -> : ^^^ ->"d" : "d" -> : ^^^ ->e : "e" -> : ^^^ ->"e" : "e" -> : ^^^ ->f : "f" -> : ^^^ ->"f" : "f" -> : ^^^ ->g : "g" -> : ^^^ ->"g" : "g" -> : ^^^ -} - -// This will not work for several reasons: -// - first because the constraint of type parameter `Arg` is generic, -// so attempting to narrow the type of `arg` in the `if` would result in type `Arg & LeftIn`, -// which when substituted in the conditional return type, would not further resolve that conditional type -// - second because the `else` branch would never work because we don't narrow the type of `arg` to `Arg & RightIn` -function conditionalProducingIf<LeftIn, RightIn, LeftOut, RightOut, Arg extends LeftIn | RightIn>( ->conditionalProducingIf : <LeftIn, RightIn, LeftOut, RightOut, Arg extends LeftIn | RightIn>(arg: Arg, cond: (arg: LeftIn | RightIn) => arg is LeftIn, produceLeftOut: (arg: LeftIn) => LeftOut, produceRightOut: (arg: RightIn) => RightOut) => Arg extends LeftIn ? LeftOut : Arg extends RightIn ? RightOut : never -> : ^ ^^ ^^ ^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^ - - arg: Arg, ->arg : Arg -> : ^^^ - - cond: (arg: LeftIn | RightIn) => arg is LeftIn, ->cond : (arg: LeftIn | RightIn) => arg is LeftIn -> : ^ ^^ ^^^^^ ->arg : LeftIn | RightIn -> : ^^^^^^^^^^^^^^^^ - - produceLeftOut: (arg: LeftIn) => LeftOut, ->produceLeftOut : (arg: LeftIn) => LeftOut -> : ^ ^^ ^^^^^ ->arg : LeftIn -> : ^^^^^^ - - produceRightOut: (arg: RightIn) => RightOut): ->produceRightOut : (arg: RightIn) => RightOut -> : ^ ^^ ^^^^^ ->arg : RightIn -> : ^^^^^^^ - - Arg extends LeftIn ? LeftOut : Arg extends RightIn ? RightOut : never -{ - if (cond(arg)) { ->cond(arg) : boolean -> : ^^^^^^^ ->cond : (arg: LeftIn | RightIn) => arg is LeftIn -> : ^ ^^ ^^^^^ ->arg : Arg -> : ^^^ - - return produceLeftOut(arg); ->produceLeftOut(arg) : LeftOut -> : ^^^^^^^ ->produceLeftOut : (arg: LeftIn) => LeftOut -> : ^ ^^ ^^^^^ ->arg : Arg & LeftIn -> : ^^^^^^^^^^^^ - - } else { - return produceRightOut(arg as RightIn); ->produceRightOut(arg as RightIn) : RightOut -> : ^^^^^^^^ ->produceRightOut : (arg: RightIn) => RightOut -> : ^ ^^ ^^^^^ ->arg as RightIn : RightIn -> : ^^^^^^^ ->arg : Arg -> : ^^^ - } -} - -interface Animal { - name: string; ->name : string -> : ^^^^^^ -} - -interface Dog extends Animal { - bark: () => string; ->bark : () => string -> : ^^^^^^ -} - -// This would be unsafe to narrow. -declare function isDog(x: Animal): x is Dog; ->isDog : (x: Animal) => x is Dog -> : ^ ^^ ^^^^^ ->x : Animal -> : ^^^^^^ - -declare function doggy(x: Dog): number; ->doggy : (x: Dog) => number -> : ^ ^^ ^^^^^ ->x : Dog -> : ^^^ - -function f12<T extends Animal>(x: T): T extends Dog ? number : string { ->f12 : <T extends Animal>(x: T) => T extends Dog ? number : string -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->x : T -> : ^ - - if (isDog(x)) { // `x` has type `T & Dog` here ->isDog(x) : boolean -> : ^^^^^^^ ->isDog : (x: Animal) => x is Dog -> : ^ ^^ ^^^^^ ->x : T -> : ^ - - return doggy(x); ->doggy(x) : number -> : ^^^^^^ ->doggy : (x: Dog) => number -> : ^ ^^ ^^^^^ ->x : T & Dog -> : ^^^^^^^ - } - return ""; // Error: Should not work because we can't express "not a Dog" in the type system ->"" : "" -> : ^^ -} - -// Cannot narrow `keyof` too eagerly or something like the below breaks -function f<Entry extends { [index: string]: number | boolean }, EntryId extends keyof Entry>(entry: EntryId): Entry[EntryId] { ->f : <Entry extends { [index: string]: number | boolean; }, EntryId extends keyof Entry>(entry: EntryId) => Entry[EntryId] -> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->index : string -> : ^^^^^^ ->entry : EntryId -> : ^^^^^^^ - - const entries = {} as Entry; ->entries : Entry -> : ^^^^^ ->{} as Entry : Entry -> : ^^^^^ ->{} : {} -> : ^^ - - return entries[entry]; ->entries[entry] : Entry[EntryId] -> : ^^^^^^^^^^^^^^ ->entries : Entry -> : ^^^^^ ->entry : EntryId -> : ^^^^^^^ -} - -// Works the same as before -declare function takeA(val: 'A'): void; ->takeA : (val: "A") => void -> : ^ ^^ ^^^^^ ->val : "A" -> : ^^^ - -export function bounceAndTakeIfA<AB extends 'A' | 'B'>(value: AB): AB { ->bounceAndTakeIfA : <AB extends "A" | "B">(value: AB) => AB -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->value : AB -> : ^^ - - if (value === 'A') { ->value === 'A' : boolean -> : ^^^^^^^ ->value : AB -> : ^^ ->'A' : "A" -> : ^^^ - - takeA(value); ->takeA(value) : void -> : ^^^^ ->takeA : (val: "A") => void -> : ^ ^^ ^^^^^ ->value : "A" -> : ^^^ - - takeAB(value); ->takeAB(value) : void -> : ^^^^ ->takeAB : (val: AB) => void -> : ^ ^^ ^^^^^ ->value : AB -> : ^^ - - return value; ->value : AB -> : ^^ - } - - return value; ->value : AB -> : ^^ - - function takeAB(val: AB): void {} ->takeAB : (val: AB) => void -> : ^ ^^ ^^^^^ ->val : AB -> : ^^ -} - -// Works the same as before -export function bbb<AB extends "a" | "b">(value: AB): "a" { ->bbb : <AB extends "a" | "b">(value: AB) => "a" -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->value : AB -> : ^^ - - if (value === "a") { ->value === "a" : boolean -> : ^^^^^^^ ->value : AB -> : ^^ ->"a" : "a" -> : ^^^ - - return value; ->value : "a" -> : ^^^ - } - return "a"; ->"a" : "a" -> : ^^^ -} - -class Unnamed { ->Unnamed : Unnamed -> : ^^^^^^^ - - root!: { name: string }; ->root : { name: string; } -> : ^^^^^^^^ ^^^ ->name : string -> : ^^^^^^ - - // Error: No narrowing because parameter is optional but `T` doesn't allow for undefined - name<T extends string>(name?: T): T extends string ? this : T extends undefined ? string : never { ->name : <T extends string>(name?: T) => T extends string ? this : T extends undefined ? string : never -> : ^ ^^^^^^^^^ ^^ ^^^ ^^^^^ ->name : T | undefined -> : ^^^^^^^^^^^^^ - - if (typeof name === 'undefined') { ->typeof name === 'undefined' : boolean -> : ^^^^^^^ ->typeof name : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->name : T | undefined -> : ^^^^^^^^^^^^^ ->'undefined' : "undefined" -> : ^^^^^^^^^^^ - - return this.root.name; ->this.root.name : string -> : ^^^^^^ ->this.root : { name: string; } -> : ^^^^^^^^ ^^^ ->this : this -> : ^^^^ ->root : { name: string; } -> : ^^^^^^^^ ^^^ ->name : string -> : ^^^^^^ - } - return this; ->this : this -> : ^^^^ - } - - // Good conditional - name2<T extends string | undefined>(name?: T): T extends string ? this : T extends undefined ? string : never { ->name2 : <T extends string | undefined>(name?: T) => T extends string ? this : T extends undefined ? string : never -> : ^ ^^^^^^^^^ ^^ ^^^ ^^^^^ ->name : T | undefined -> : ^^^^^^^^^^^^^ - - if (typeof name === 'undefined') { ->typeof name === 'undefined' : boolean -> : ^^^^^^^ ->typeof name : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->name : T | undefined -> : ^^^^^^^^^^^^^ ->'undefined' : "undefined" -> : ^^^^^^^^^^^ - - return this.root.name; // Ok ->this.root.name : string -> : ^^^^^^ ->this.root : { name: string; } -> : ^^^^^^^^ ^^^ ->this : this -> : ^^^^ ->root : { name: string; } -> : ^^^^^^^^ ^^^ ->name : string -> : ^^^^^^ - } - this.root.name = name; ->this.root.name = name : string -> : ^^^^^^ ->this.root.name : string -> : ^^^^^^ ->this.root : { name: string; } -> : ^^^^^^^^ ^^^ ->this : this -> : ^^^^ ->root : { name: string; } -> : ^^^^^^^^ ^^^ ->name : string -> : ^^^^^^ ->name : string -> : ^^^^^^ - - return this; // Ok ->this : this -> : ^^^^ - } - - // Good conditional, wrong return expressions - name3<T extends string | undefined>(name?: T): T extends string ? this : T extends undefined ? string : never { ->name3 : <T extends string | undefined>(name?: T) => T extends string ? this : T extends undefined ? string : never -> : ^ ^^^^^^^^^ ^^ ^^^ ^^^^^ ->name : T | undefined -> : ^^^^^^^^^^^^^ - - if (typeof name === 'undefined') { ->typeof name === 'undefined' : boolean -> : ^^^^^^^ ->typeof name : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->name : T | undefined -> : ^^^^^^^^^^^^^ ->'undefined' : "undefined" -> : ^^^^^^^^^^^ - - return this; // Error ->this : this -> : ^^^^ - } - this.root.name = name; ->this.root.name = name : string -> : ^^^^^^ ->this.root.name : string -> : ^^^^^^ ->this.root : { name: string; } -> : ^^^^^^^^ ^^^ ->this : this -> : ^^^^ ->root : { name: string; } -> : ^^^^^^^^ ^^^ ->name : string -> : ^^^^^^ ->name : string -> : ^^^^^^ - - return name; // Error ->name : T & {} -> : ^^^^^^ - } -} - -// Conditional expressions -interface Aa { - 1: number; ->1 : number -> : ^^^^^^ - - 2: string; ->2 : string -> : ^^^^^^ - - 3: boolean; ->3 : boolean -> : ^^^^^^^ -} - -function trivialConditional<T extends 1 | 2 | 3>(x: T): Aa[T] { ->trivialConditional : <T extends 1 | 2 | 3>(x: T) => Aa[T] -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->x : T -> : ^ - - if (x !== 1) { ->x !== 1 : boolean -> : ^^^^^^^ ->x : T -> : ^ ->1 : 1 -> : ^ - - return x === 2 ? "" : true; ->x === 2 ? "" : true : true | "" -> : ^^^^^^^^^ ->x === 2 : boolean -> : ^^^^^^^ ->x : T -> : ^ ->2 : 2 -> : ^ ->"" : "" -> : ^^ ->true : true -> : ^^^^ - } - else { - return 0; ->0 : 0 -> : ^ - } -} - -function conditional<T extends boolean>(x: T): ->conditional : <T extends boolean>(x: T) => T extends true ? 1 : T extends false ? 2 : never -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->x : T -> : ^ - - T extends true ? 1 : T extends false ? 2 : never { ->true : true -> : ^^^^ ->false : false -> : ^^^^^ - - return x ? 1 : 2; // Ok ->x ? 1 : 2 : 1 | 2 -> : ^^^^^ ->x : T -> : ^ ->1 : 1 -> : ^ ->2 : 2 -> : ^ -} - -function contextualConditional<T extends "a" | "b">( ->contextualConditional : <T extends "a" | "b">(x: T) => T extends "a" ? "a" : T extends "b" ? number : never -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ - - x: T ->x : T -> : ^ - -): T extends "a" ? "a" : T extends "b" ? number : never { - return x === "a" ? x : parseInt(x); // Ok ->x === "a" ? x : parseInt(x) : number | "a" -> : ^^^^^^^^^^^^ ->x === "a" : boolean -> : ^^^^^^^ ->x : T -> : ^ ->"a" : "a" -> : ^^^ ->x : "a" -> : ^^^ ->parseInt(x) : number -> : ^^^^^^ ->parseInt : (string: string, radix?: number) => number -> : ^ ^^ ^^ ^^^ ^^^^^ ->x : "b" -> : ^^^ -} - -function conditionalWithError<T extends "a" | "b">( ->conditionalWithError : <T extends "a" | "b">(x: T) => T extends "a" ? number : T extends "b" ? string : never -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ - - x: T ->x : T -> : ^ - -): T extends "a" ? number : T extends "b" ? string : never { - return x === "a" ? x : parseInt(x); // Error ->x === "a" ? x : parseInt(x) : number | "a" -> : ^^^^^^^^^^^^ ->x === "a" : boolean -> : ^^^^^^^ ->x : T -> : ^ ->"a" : "a" -> : ^^^ ->x : "a" -> : ^^^ ->parseInt(x) : number -> : ^^^^^^ ->parseInt : (string: string, radix?: number) => number -> : ^ ^^ ^^ ^^^ ^^^^^ ->x : "b" -> : ^^^ -} - -// Multiple indexed type reductions -interface BB { - "a": number; ->"a" : number -> : ^^^^^^ - - [y: number]: string; ->y : number -> : ^^^^^^ -} - -interface AA<T extends keyof BB> { - "c": BB[T]; ->"c" : BB[T] -> : ^^^^^ - - "d": boolean, ->"d" : boolean -> : ^^^^^^^ -} - -function reduction<T extends keyof BB, U extends "c" | "d">(x: T, y: U): AA<T>[U] { ->reduction : <T extends keyof BB, U extends "c" | "d">(x: T, y: U) => AA<T>[U] -> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^ ->x : T -> : ^ ->y : U -> : ^ - - if (y === "c" && x === "a") { ->y === "c" && x === "a" : boolean -> : ^^^^^^^ ->y === "c" : boolean -> : ^^^^^^^ ->y : U -> : ^ ->"c" : "c" -> : ^^^ ->x === "a" : boolean -> : ^^^^^^^ ->x : T -> : ^ ->"a" : "a" -> : ^^^ - - // AA<T>[U='c'] -> BB[T] - // BB[T='a'] -> number - return 0; // Ok ->0 : 0 -> : ^ - } - - return undefined as never; ->undefined as never : never -> : ^^^^^ ->undefined : undefined -> : ^^^^^^^^^ -} - -// Substitution types are not narrowed -function subsCond<T extends 1 | 2 | 3>( ->subsCond : <T extends 1 | 2 | 3>(x: T) => T extends 1 | 2 ? T extends 1 ? string : T extends 2 ? boolean : never : T extends 3 ? number : never -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ - - x: T, ->x : T -> : ^ - -): T extends 1 | 2 - ? T extends 1 - ? string - : T extends 2 - ? boolean - : never - : T extends 3 - ? number - : never { - if (x === 1) { ->x === 1 : boolean -> : ^^^^^^^ ->x : T -> : ^ ->1 : 1 -> : ^ - - return ""; ->"" : "" -> : ^^ - - } else if (x == 2) { ->x == 2 : boolean -> : ^^^^^^^ ->x : T -> : ^ ->2 : 2 -> : ^ - - return true; ->true : true -> : ^^^^ - } - return 3; ->3 : 3 -> : ^ -} - - -// Unsafe: check types overlap -declare function q(x: object): x is { b: number }; ->q : (x: object) => x is { b: number; } -> : ^ ^^ ^^^^^ ->x : object -> : ^^^^^^ ->b : number -> : ^^^^^^ - -function foo<T extends { a: string } | { b: number }>( ->foo : <T extends { a: string; } | { b: number; }>(x: T) => T extends { a: string; } ? number : T extends { b: number; } ? string : never -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->a : string -> : ^^^^^^ ->b : number -> : ^^^^^^ - - x: T, ->x : T -> : ^ - -): T extends { a: string } ? number : T extends { b: number } ? string : never { ->a : string -> : ^^^^^^ ->b : number -> : ^^^^^^ - - if (q(x)) { ->q(x) : boolean -> : ^^^^^^^ ->q : (x: object) => x is { b: number; } -> : ^ ^^ ^^^^^ ->x : { a: string; } | { b: number; } -> : ^^^^^ ^^^^^^^^^^^ ^^^ - - x.b; ->x.b : number -> : ^^^^^^ ->x : { b: number; } -> : ^^^^^ ^^^ ->b : number -> : ^^^^^^ - - return ""; ->"" : "" -> : ^^ - } - x.a; ->x.a : string -> : ^^^^^^ ->x : { a: string; } -> : ^^^^^ ^^^ ->a : string -> : ^^^^^^ - - return 1; ->1 : 1 -> : ^ -} - -let y = { a: "", b: 1 } ->y : { a: string; b: number; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^ ->{ a: "", b: 1 } : { a: string; b: number; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^ ->a : string -> : ^^^^^^ ->"" : "" -> : ^^ ->b : number -> : ^^^^^^ ->1 : 1 -> : ^ - -const r = foo<{ a: string }>(y); // type says number but actually string ->r : number -> : ^^^^^^ ->foo<{ a: string }>(y) : number -> : ^^^^^^ ->foo : <T extends { a: string; } | { b: number; }>(x: T) => T extends { a: string; } ? number : T extends { b: number; } ? string : never -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->a : string -> : ^^^^^^ ->y : { a: string; b: number; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^ - -type HelperCond<T, A, R1, B, R2> = T extends A ? R1 : T extends B ? R2 : never; ->HelperCond : HelperCond<T, A, R1, B, R2> -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -// We don't narrow the return type because the conditionals are not distributive -function foo2<U extends string | number, V extends boolean>(x: U, y: V): ->foo2 : <U extends string | number, V extends boolean>(x: U, y: V) => HelperCond<{ x: U; y: V; }, { x: string; y: true; }, 1, { x: number; y: false; }, 2> -> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^ ->x : U -> : ^ ->y : V -> : ^ - - HelperCond<{ x: U, y: V }, ->x : U -> : ^ ->y : V -> : ^ - - { x: string, y: true }, 1, ->x : string -> : ^^^^^^ ->y : true -> : ^^^^ ->true : true -> : ^^^^ - - { x: number, y: false }, 2> { ->x : number -> : ^^^^^^ ->y : false -> : ^^^^^ ->false : false -> : ^^^^^ - - if (typeof x === "string" && y === true) { ->typeof x === "string" && y === true : boolean -> : ^^^^^^^ ->typeof x === "string" : boolean -> : ^^^^^^^ ->typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->x : U -> : ^ ->"string" : "string" -> : ^^^^^^^^ ->y === true : boolean -> : ^^^^^^^ ->y : V -> : ^ ->true : true -> : ^^^^ - - return 1; // Error ->1 : 1 -> : ^ - } - if (typeof x === "number" && y === false) { ->typeof x === "number" && y === false : boolean -> : ^^^^^^^ ->typeof x === "number" : boolean -> : ^^^^^^^ ->typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->x : U -> : ^ ->"number" : "number" -> : ^^^^^^^^ ->y === false : boolean -> : ^^^^^^^ ->y : V -> : ^ ->false : false -> : ^^^^^ - - return 2; // Error ->2 : 2 -> : ^ - } - return 0; // Error ->0 : 0 -> : ^ -} - -// From https://github.com/microsoft/TypeScript/issues/24929#issue-332087943 -declare function isString(s: unknown): s is string; ->isString : (s: unknown) => s is string -> : ^ ^^ ^^^^^ ->s : unknown -> : ^^^^^^^ - -// capitalize a string or each element of an array of strings -function capitalize<T extends string | string[]>( ->capitalize : <T extends string | string[]>(input: T) => T extends string[] ? string[] : T extends string ? string : never -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ - - input: T ->input : T -> : ^ - -): T extends string[] ? string[] : T extends string ? string : never { - if (isString(input)) { ->isString(input) : boolean -> : ^^^^^^^ ->isString : (s: unknown) => s is string -> : ^ ^^ ^^^^^ ->input : string | string[] -> : ^^^^^^^^^^^^^^^^^ - - return input[0].toUpperCase() + input.slice(1); // Ok ->input[0].toUpperCase() + input.slice(1) : string -> : ^^^^^^ ->input[0].toUpperCase() : string -> : ^^^^^^ ->input[0].toUpperCase : () => string -> : ^^^^^^ ->input[0] : string -> : ^^^^^^ ->input : string -> : ^^^^^^ ->0 : 0 -> : ^ ->toUpperCase : () => string -> : ^^^^^^ ->input.slice(1) : string -> : ^^^^^^ ->input.slice : (start?: number, end?: number) => string -> : ^ ^^^ ^^ ^^^ ^^^^^ ->input : string -> : ^^^^^^ ->slice : (start?: number, end?: number) => string -> : ^ ^^^ ^^ ^^^ ^^^^^ ->1 : 1 -> : ^ - - } else { - return input.map(elt => capitalize(elt)); // Ok ->input.map(elt => capitalize(elt)) : string[] -> : ^^^^^^^^ ->input.map : <U>(callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => U[] -> : ^ ^^ ^^^ ^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^ ->input : string[] -> : ^^^^^^^^ ->map : <U>(callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => U[] -> : ^ ^^ ^^^ ^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^ ->elt => capitalize(elt) : (elt: string) => string -> : ^ ^^^^^^^^^^^^^^^^^^^ ->elt : string -> : ^^^^^^ ->capitalize(elt) : string -> : ^^^^^^ ->capitalize : <T extends string | string[]>(input: T) => T extends string[] ? string[] : T extends string ? string : never -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->elt : string -> : ^^^^^^ - } -} - -function badCapitalize<T extends string | string[]>( ->badCapitalize : <T extends string | string[]>(input: T) => T extends string[] ? string[] : T extends string ? string : never -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ - - input: T ->input : T -> : ^ - -): T extends string[] ? string[] : T extends string ? string : never { - if (isString(input)) { ->isString(input) : boolean -> : ^^^^^^^ ->isString : (s: unknown) => s is string -> : ^ ^^ ^^^^^ ->input : string | string[] -> : ^^^^^^^^^^^^^^^^^ - - return input[0].toUpperCase() + input.slice(1); // Ok ->input[0].toUpperCase() + input.slice(1) : string -> : ^^^^^^ ->input[0].toUpperCase() : string -> : ^^^^^^ ->input[0].toUpperCase : () => string -> : ^^^^^^ ->input[0] : string -> : ^^^^^^ ->input : string -> : ^^^^^^ ->0 : 0 -> : ^ ->toUpperCase : () => string -> : ^^^^^^ ->input.slice(1) : string -> : ^^^^^^ ->input.slice : (start?: number, end?: number) => string -> : ^ ^^^ ^^ ^^^ ^^^^^ ->input : string -> : ^^^^^^ ->slice : (start?: number, end?: number) => string -> : ^ ^^^ ^^ ^^^ ^^^^^ ->1 : 1 -> : ^ - - } else { - return input[0].toUpperCase() + input.slice(1); // Bad, error ->input[0].toUpperCase() + input.slice(1) : string -> : ^^^^^^ ->input[0].toUpperCase() : string -> : ^^^^^^ ->input[0].toUpperCase : () => string -> : ^^^^^^ ->input[0] : string -> : ^^^^^^ ->input : string[] -> : ^^^^^^^^ ->0 : 0 -> : ^ ->toUpperCase : () => string -> : ^^^^^^ ->input.slice(1) : string[] -> : ^^^^^^^^ ->input.slice : (start?: number, end?: number) => string[] -> : ^ ^^^ ^^ ^^^ ^^^^^^^^^^^^^ ->input : string[] -> : ^^^^^^^^ ->slice : (start?: number, end?: number) => string[] -> : ^ ^^^ ^^ ^^^ ^^^^^^^^^^^^^ ->1 : 1 -> : ^ - } -} - -// No narrowing because conditional's extends type is different from type parameter constraint types -function voidRet<T extends { a: string } | undefined>( ->voidRet : <T extends { a: string; } | undefined>(x: T) => T extends {} ? void : T extends undefined ? number : never -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->a : string -> : ^^^^^^ - - x: T ->x : T -> : ^ - -): T extends {} ? void : T extends undefined ? number : never { - if (x) { ->x : T -> : ^ - - return; - } - return 1; ->1 : 1 -> : ^ -} - -// Multiple type parameters at once -function woo<T extends string | number, U extends string | number>( ->woo : <T extends string | number, U extends string | number>(x: T, y: U) => T extends string ? U extends string ? 1 : U extends number ? 2 : never : T extends number ? U extends number ? 3 : U extends string ? 4 : never : never -> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^ - - x: T, ->x : T -> : ^ - - y: U, ->y : U -> : ^ - -): T extends string - ? U extends string - ? 1 - : U extends number - ? 2 - : never - : T extends number - ? U extends number - ? 3 - : U extends string - ? 4 - : never - : never { - if (typeof x === "number" && typeof y === "string") { ->typeof x === "number" && typeof y === "string" : boolean -> : ^^^^^^^ ->typeof x === "number" : boolean -> : ^^^^^^^ ->typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->x : T -> : ^ ->"number" : "number" -> : ^^^^^^^^ ->typeof y === "string" : boolean -> : ^^^^^^^ ->typeof y : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->y : U -> : ^ ->"string" : "string" -> : ^^^^^^^^ - - return 1; // Good error ->1 : 1 -> : ^ - } - return undefined as any; ->undefined as any : any -> : ^^^ ->undefined : undefined -> : ^^^^^^^^^ -} - -function ttt<T extends string | number, U extends string | number>( ->ttt : <T extends string | number, U extends string | number>(x: T, y: U) => T extends string ? U extends string ? 1 : U extends number ? 2 : never : T extends number ? U extends number ? 3 : U extends string ? 4 : never : never -> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^ - - x: T, ->x : T -> : ^ - - y: U, ->y : U -> : ^ - -): T extends string - ? U extends string - ? 1 - : U extends number - ? 2 - : never - : T extends number - ? U extends number - ? 3 - : U extends string - ? 4 - : never - : never { - if (typeof x === "number" && typeof y === "string") { ->typeof x === "number" && typeof y === "string" : boolean -> : ^^^^^^^ ->typeof x === "number" : boolean -> : ^^^^^^^ ->typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->x : T -> : ^ ->"number" : "number" -> : ^^^^^^^^ ->typeof y === "string" : boolean -> : ^^^^^^^ ->typeof y : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->y : U -> : ^ ->"string" : "string" -> : ^^^^^^^^ - - return 4; // Ok ->4 : 4 -> : ^ - } - - return undefined as any; ->undefined as any : any -> : ^^^ ->undefined : undefined -> : ^^^^^^^^^ -} - -// Shadowing of the narrowed reference -function shadowing<T extends 1 | 2>(x: T): T extends 1 ? number : T extends 2 ? string : never { ->shadowing : <T extends 1 | 2>(x: T) => T extends 1 ? number : T extends 2 ? string : never -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->x : T -> : ^ - - if (true) { ->true : true -> : ^^^^ - - let x: number = Math.random() ? 1 : 2; ->x : number -> : ^^^^^^ ->Math.random() ? 1 : 2 : 1 | 2 -> : ^^^^^ ->Math.random() : number -> : ^^^^^^ ->Math.random : () => number -> : ^^^^^^ ->Math : Math -> : ^^^^ ->random : () => number -> : ^^^^^^ ->1 : 1 -> : ^ ->2 : 2 -> : ^ - - if (x === 1) { ->x === 1 : boolean -> : ^^^^^^^ ->x : number -> : ^^^^^^ ->1 : 1 -> : ^ - - return 1; // Error ->1 : 1 -> : ^ - } - return ""; // Error ->"" : "" -> : ^^ - } -} - -function noShadowing<T extends 1 | 2>(x: T): T extends 1 ? number : T extends 2 ? string : never { ->noShadowing : <T extends 1 | 2>(x: T) => T extends 1 ? number : T extends 2 ? string : never -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->x : T -> : ^ - - if (true) { ->true : true -> : ^^^^ - - if (x === 1) { ->x === 1 : boolean -> : ^^^^^^^ ->x : T -> : ^ ->1 : 1 -> : ^ - - return 1; // Ok ->1 : 1 -> : ^ - } - return ""; // Ok ->"" : "" -> : ^^ - } -} - -// If the narrowing reference is out of scope, we simply won't narrow its type -declare let someX: boolean; ->someX : boolean -> : ^^^^^^^ - -function scope2<T extends boolean>(a: T): T extends true ? 1 : T extends false ? 2 : never { ->scope2 : <T extends boolean>(a: T) => T extends true ? 1 : T extends false ? 2 : never -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->a : T -> : ^ ->true : true -> : ^^^^ ->false : false -> : ^^^^^ - - if ((true)) { ->(true) : true -> : ^^^^ ->true : true -> : ^^^^ - - const someX = a; ->someX : T -> : ^ ->a : T -> : ^ - - if (someX) { // We narrow `someX` and the return type here ->someX : T -> : ^ - - return 1; ->1 : 1 -> : ^ - } - } - if (!someX) { // This is a different `someX`, so we don't narrow here ->!someX : boolean -> : ^^^^^^^ ->someX : boolean -> : ^^^^^^^ - - return 2; ->2 : 2 -> : ^ - } - - return undefined as any; ->undefined as any : any -> : ^^^ ->undefined : undefined -> : ^^^^^^^^^ -} - -function moreShadowing<T extends 1 | 2>(x: T): T extends 1 ? number : T extends 2 ? string : never { ->moreShadowing : <T extends 1 | 2>(x: T) => T extends 1 ? number : T extends 2 ? string : never -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->x : T -> : ^ - - if (x === 2) { ->x === 2 : boolean -> : ^^^^^^^ ->x : T -> : ^ ->2 : 2 -> : ^ - - let x: number = Math.random() ? 1 : 2; ->x : number -> : ^^^^^^ ->Math.random() ? 1 : 2 : 1 | 2 -> : ^^^^^ ->Math.random() : number -> : ^^^^^^ ->Math.random : () => number -> : ^^^^^^ ->Math : Math -> : ^^^^ ->random : () => number -> : ^^^^^^ ->1 : 1 -> : ^ ->2 : 2 -> : ^ - - if (x === 1) { ->x === 1 : boolean -> : ^^^^^^^ ->x : number -> : ^^^^^^ ->1 : 1 -> : ^ - - return 1; // Error ->1 : 1 -> : ^ - } - return ""; // Ok ->"" : "" -> : ^^ - } - return 0; // Ok ->0 : 0 -> : ^ -} - -// This would be unsafe to narrow due to `infer` type. -function withInfer<T extends [string] | number>(x: T): T extends [infer R] ? R : T extends number ? boolean : never { ->withInfer : <T extends [string] | number>(x: T) => T extends [infer R] ? R : T extends number ? boolean : never -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->x : T -> : ^ - - if (typeof x === "number") { ->typeof x === "number" : boolean -> : ^^^^^^^ ->typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->x : T -> : ^ ->"number" : "number" -> : ^^^^^^^^ - - return true; ->true : true -> : ^^^^ - } - return ""; ->"" : "" -> : ^^ -} - -const withInferResult = withInfer(["a"] as const); // The type says it returns `"a"`, but the function actually returns `""`. ->withInferResult : "a" -> : ^^^ ->withInfer(["a"] as const) : "a" -> : ^^^ ->withInfer : <T extends [string] | number>(x: T) => T extends [infer R] ? R : T extends number ? boolean : never -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->["a"] as const : ["a"] -> : ^^^^^ ->["a"] : ["a"] -> : ^^^^^ ->"a" : "a" -> : ^^^ - -// Ok -async function abool<T extends true | false>(x: T): Promise<T extends true ? 1 : T extends false ? 2 : never> { ->abool : <T extends true | false>(x: T) => Promise<T extends true ? 1 : T extends false ? 2 : never> -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->true : true -> : ^^^^ ->false : false -> : ^^^^^ ->x : T -> : ^ ->true : true -> : ^^^^ ->false : false -> : ^^^^^ - - if (x) { ->x : T -> : ^ - - return 1; ->1 : 1 -> : ^ - } - return 2; ->2 : 2 -> : ^ -} - -// Ok -function* bbool<T extends true | false>(x: T): Generator<number, T extends true ? 1 : T extends false ? 2 : never, unknown> { ->bbool : <T extends true | false>(x: T) => Generator<number, T extends true ? 1 : T extends false ? 2 : never, unknown> -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->true : true -> : ^^^^ ->false : false -> : ^^^^^ ->x : T -> : ^ ->true : true -> : ^^^^ ->false : false -> : ^^^^^ - - yield 3; ->yield 3 : unknown -> : ^^^^^^^ ->3 : 3 -> : ^ - - if (x) { ->x : T -> : ^ - - return 1; ->1 : 1 -> : ^ - } - return 2; ->2 : 2 -> : ^ -} - -// We don't do the same type of narrowing for `yield` statements -function* cbool<T extends true | false>(x: T): Generator<T extends true ? 1 : T extends false ? 2 : never, number, unknown> { ->cbool : <T extends true | false>(x: T) => Generator<T extends true ? 1 : T extends false ? 2 : never, number, unknown> -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->true : true -> : ^^^^ ->false : false -> : ^^^^^ ->x : T -> : ^ ->true : true -> : ^^^^ ->false : false -> : ^^^^^ - - if (x) { ->x : T -> : ^ - - yield 1; ->yield 1 : unknown -> : ^^^^^^^ ->1 : 1 -> : ^ - } - yield 2; ->yield 2 : unknown -> : ^^^^^^^ ->2 : 2 -> : ^ - - return 0; ->0 : 0 -> : ^ -} - -// From #33912 -abstract class Operation<T, R> { ->Operation : Operation<T, R> -> : ^^^^^^^^^^^^^^^ - - abstract perform(t: T): R; ->perform : (t: T) => R -> : ^ ^^ ^^^^^ ->t : T -> : ^ -} - -type ConditionalReturnType<T, R, EOp extends Operation<T, R> | undefined> = ->ConditionalReturnType : ConditionalReturnType<T, R, EOp> -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - EOp extends Operation<T, R> ? R : EOp extends undefined ? T | R : never; - - -class ConditionalOperation< ->ConditionalOperation : ConditionalOperation<T, R, EOp> -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - T, - R, - EOp extends Operation<T, R> | undefined, -> extends Operation<T, ConditionalReturnType<T, R, EOp>> { ->Operation : Operation<T, ConditionalReturnType<T, R, EOp>> -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - constructor( - private predicate: (value: T) => boolean, ->predicate : (value: T) => boolean -> : ^ ^^ ^^^^^ ->value : T -> : ^ - - private thenOp: Operation<T, R>, ->thenOp : Operation<T, R> -> : ^^^^^^^^^^^^^^^ - - private elseOp?: EOp, ->elseOp : EOp | undefined -> : ^^^^^^^^^^^^^^^ - - ) { - super(); ->super() : void -> : ^^^^ ->super : typeof Operation -> : ^^^^^^^^^^^^^^^^ - } - - // We won't try to narrow the return type because `T` is declared on the class and we don't analyze this case. - perform(t: T): ConditionalReturnType<T, R, EOp> { ->perform : (t: T) => ConditionalReturnType<T, R, EOp> -> : ^ ^^ ^^^^^ ->t : T -> : ^ - - if (this.predicate(t)) { ->this.predicate(t) : boolean -> : ^^^^^^^ ->this.predicate : (value: T) => boolean -> : ^ ^^ ^^^^^ ->this : this -> : ^^^^ ->predicate : (value: T) => boolean -> : ^ ^^ ^^^^^ ->t : T -> : ^ - - return this.thenOp.perform(t); // Bad: this is assignable to all of the branches of the conditional, but we still can't return it ->this.thenOp.perform(t) : R -> : ^ ->this.thenOp.perform : (t: T) => R -> : ^ ^^^^^^^^^ ->this.thenOp : Operation<T, R> -> : ^^^^^^^^^^^^^^^ ->this : this -> : ^^^^ ->thenOp : Operation<T, R> -> : ^^^^^^^^^^^^^^^ ->perform : (t: T) => R -> : ^ ^^^^^^^^^ ->t : T -> : ^ - - } else if (typeof this.elseOp !== "undefined") { ->typeof this.elseOp !== "undefined" : boolean -> : ^^^^^^^ ->typeof this.elseOp : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->this.elseOp : EOp | undefined -> : ^^^^^^^^^^^^^^^ ->this : this -> : ^^^^ ->elseOp : EOp | undefined -> : ^^^^^^^^^^^^^^^ ->"undefined" : "undefined" -> : ^^^^^^^^^^^ - - return this.elseOp.perform(t); // Would be ok ->this.elseOp.perform(t) : R -> : ^ ->this.elseOp.perform : (t: T) => R -> : ^ ^^^^^^^^^ ->this.elseOp : Operation<T, R> -> : ^^^^^^^^^^^^^^^ ->this : this -> : ^^^^ ->elseOp : Operation<T, R> -> : ^^^^^^^^^^^^^^^ ->perform : (t: T) => R -> : ^ ^^^^^^^^^ ->t : T -> : ^ - - } else { - return t; // Would be ok ->t : T -> : ^ - } - } -} - -// Like the version above, we will not attempt to narrow because there's more than one reference to `T`, -// because `T` shows up in the type of `predicate`. -function perform<T, R, EOp extends Operation<T, R> | undefined>( ->perform : <T, R, EOp extends Operation<T, R> | undefined>(t: T, predicate: (value: T) => boolean, thenOp: Operation<T, R>, elseOp?: EOp) => ConditionalReturnType<T, R, EOp> -> : ^ ^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^ ^^^^^ - - t: T, ->t : T -> : ^ - - predicate: (value: T) => boolean, ->predicate : (value: T) => boolean -> : ^ ^^ ^^^^^ ->value : T -> : ^ - - thenOp: Operation<T, R>, ->thenOp : Operation<T, R> -> : ^^^^^^^^^^^^^^^ - - elseOp?: EOp, ->elseOp : EOp | undefined -> : ^^^^^^^^^^^^^^^ - - ): ConditionalReturnType<T, R, EOp> { - if (predicate(t)) { ->predicate(t) : boolean -> : ^^^^^^^ ->predicate : (value: T) => boolean -> : ^ ^^ ^^^^^ ->t : T -> : ^ - - return thenOp.perform(t); // Bad: this is assignable to all of the branches of the conditional, but we still can't return it ->thenOp.perform(t) : R -> : ^ ->thenOp.perform : (t: T) => R -> : ^ ^^^^^^^^^ ->thenOp : Operation<T, R> -> : ^^^^^^^^^^^^^^^ ->perform : (t: T) => R -> : ^ ^^^^^^^^^ ->t : T -> : ^ - - } else if (elseOp !== undefined) { ->elseOp !== undefined : boolean -> : ^^^^^^^ ->elseOp : EOp | undefined -> : ^^^^^^^^^^^^^^^ ->undefined : undefined -> : ^^^^^^^^^ - - return elseOp.perform(t); // Would be ok ->elseOp.perform(t) : R -> : ^ ->elseOp.perform : (t: T) => R -> : ^ ^^^^^^^^^ ->elseOp : Operation<T, R> -> : ^^^^^^^^^^^^^^^ ->perform : (t: T) => R -> : ^ ^^^^^^^^^ ->t : T -> : ^ - - } else { - return t; // Would be ok ->t : T -> : ^ - } -} - -// Return conditional expressions with parentheses -function returnStuff1<T extends boolean>(x: T ): T extends true ? 1 : T extends false ? 2 : never { ->returnStuff1 : <T extends boolean>(x: T) => T extends true ? 1 : T extends false ? 2 : never -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->x : T -> : ^ ->true : true -> : ^^^^ ->false : false -> : ^^^^^ - - return (x ? (1) : 2); ->(x ? (1) : 2) : 1 | 2 -> : ^^^^^ ->x ? (1) : 2 : 1 | 2 -> : ^^^^^ ->x : T -> : ^ ->(1) : 1 -> : ^ ->1 : 1 -> : ^ ->2 : 2 -> : ^ -} - -function returnStuff2<T extends 1 | 2 | "a">(x: T ): ->returnStuff2 : <T extends 1 | 2 | "a">(x: T) => T extends 1 ? "one" : T extends 2 ? "two" : T extends "a" ? 0 : never -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->x : T -> : ^ - - T extends 1 ? "one" : T extends 2 ? "two" : T extends "a" ? 0 : never { - return (typeof x === "string" ? 0 : (x === 1 ? ("one") : "two")); ->(typeof x === "string" ? 0 : (x === 1 ? ("one") : "two")) : 0 | "one" | "two" -> : ^^^^^^^^^^^^^^^^^ ->typeof x === "string" ? 0 : (x === 1 ? ("one") : "two") : 0 | "one" | "two" -> : ^^^^^^^^^^^^^^^^^ ->typeof x === "string" : boolean -> : ^^^^^^^ ->typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->x : T -> : ^ ->"string" : "string" -> : ^^^^^^^^ ->0 : 0 -> : ^ ->(x === 1 ? ("one") : "two") : "one" | "two" -> : ^^^^^^^^^^^^^ ->x === 1 ? ("one") : "two" : "one" | "two" -> : ^^^^^^^^^^^^^ ->x === 1 : boolean -> : ^^^^^^^ ->x : T -> : ^ ->1 : 1 -> : ^ ->("one") : "one" -> : ^^^^^ ->"one" : "one" -> : ^^^^^ ->"two" : "two" -> : ^^^^^ -} - -// If the conditional type's input is `never`, then it resolves to `never`: -function neverOk<T extends boolean>(x: T): T extends true ? 1 : T extends false ? 2 : never { ->neverOk : <T extends boolean>(x: T) => T extends true ? 1 : T extends false ? 2 : never -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->x : T -> : ^ ->true : true -> : ^^^^ ->false : false -> : ^^^^^ - - if (x === true) { ->x === true : boolean -> : ^^^^^^^ ->x : T -> : ^ ->true : true -> : ^^^^ - - return 1; ->1 : 1 -> : ^ - } - if (x === false) { ->x === false : boolean -> : ^^^^^^^ ->x : T -> : ^ ->false : false -> : ^^^^^ - - return 2; ->2 : 2 -> : ^ - } - return 1; ->1 : 1 -> : ^ -} diff --git a/tests/baselines/reference/dependentReturnType2.errors.txt b/tests/baselines/reference/dependentReturnType2.errors.txt deleted file mode 100644 index 4eddac31221f3..0000000000000 --- a/tests/baselines/reference/dependentReturnType2.errors.txt +++ /dev/null @@ -1,314 +0,0 @@ -file.js(155,13): error TS2322: Type 'undefined' is not assignable to type 'HelperCond<I, string, T | undefined, RegExp, SettingComposedValue<T>[]>'. -file.js(168,16): error TS2536: Type 'I' cannot be used to index type '{ [s: string]: any; }'. -file.js(185,9): error TS2322: Type 'Record<string, MyObj[]>' is not assignable to type 'HelperCond<T, string, MyObj[], undefined, Record<string, MyObj[]>>'. - - -==== file.js (3 errors) ==== - // Adapted from ts-error-deltas repos - - /** - * @template T - * @template A - * @template R1 - * @template B - * @template R2 - * @typedef {T extends A ? R1 : T extends B ? R2 : never} HelperCond - */ - - /** - * @typedef IMessage - * @property {string} [html] - * @property {Object[]} [tokens] - */ - - class NewKatex { - /** - * @param {string} s - * @returns {string} - */ - render(s) { - return ""; - } - - /** - * @template {string | IMessage} T - * @param {T} message - * @returns {T extends string ? string : T extends IMessage ? IMessage : never} - */ - renderMessage(message) { - if (typeof message === 'string') { - return this.render(message); // Ok - } - - if (!message.html?.trim()) { - return message; // Ok - } - - if (!message.tokens) { - message.tokens = []; - } - - message.html = this.render(message.html); - return message; // Ok - } - } - - /** - * @template {true | false} T - * @param {{ dollarSyntax: boolean; parenthesisSyntax: boolean; }} options - * @param {T} _isMessage - * @returns {T extends true ? (message: IMessage) => IMessage : T extends false ? (message: string) => string : never} - */ - function createKatexMessageRendering(options, _isMessage) { - const instance = new NewKatex(); - if (_isMessage) { - return (/** @type {IMessage} */ message) => instance.renderMessage(message); // Ok - } - return (/** @type {string} */ message) => instance.renderMessage(message); // Ok - } - - // File: Rocket.Chat/apps/meteor/app/settings/lib/settings.ts - - /** - * @typedef {Record<any, any>} MyObj - */ - - - /** - * @typedef {MyObj} SettingValue - */ - - /** - * @template {SettingValue} T - * @typedef {Object} SettingComposedValue - * @property {string} key - * @property {SettingValue} value - */ - - /** - * @callback SettingCallback - * @param {string} key - * @param {SettingValue} value - * @param {boolean} [initialLoad] - * @returns {void} - */ - - /** @type {{ settings: { [s: string]: any } }} */ - const Meteor = /** @type {any} */ (undefined); - /** @type {{ isRegExp(x: unknown): x is RegExp; }} */ - const _ = /** @type {any} */ (undefined); - - /** - * @param {RegExp} x - * @returns {void} - */ - function takesRegExp(x) { - return /** @type {any} */ undefined; - } - /** - * @param {string} x - * @returns {void} - */ - function takesString(x) { - return /** @type {any} */ undefined; - } - - /** - * @class NewSettingsBase - */ - class NewSettingsBase { - /** - * @template {SettingCallback | undefined} C - * @template {string | RegExp} I - * @template {SettingValue} T - * @param {I} _id - * @param {C} [callback] - * @returns {HelperCond<C, SettingCallback, void, undefined, HelperCond<I, string, T | undefined, RegExp, SettingComposedValue<T>[]>>} - */ - newGet(_id, callback) { - if (callback !== undefined) { - if (!Meteor.settings) { - return; // Ok - } - if (_id === '*') { - return Object.keys(Meteor.settings).forEach((key) => { - const value = Meteor.settings[key]; - callback(key, value); - }); - } - if (_.isRegExp(_id) && Meteor.settings) { - return Object.keys(Meteor.settings).forEach((key) => { - if (!_id.test(key)) { - return; - } - const value = Meteor.settings[key]; - callback(key, value); - }); - } - - if (typeof _id === 'string') { - const value = Meteor.settings[_id]; - if (value != null) { - callback(_id, Meteor.settings[_id]); - } - return; // Ok - } - - return; // Ok, needed for exhaustiveness check - } - - if (!Meteor.settings) { - return undefined; // Error - ~~~~~~ -!!! error TS2322: Type 'undefined' is not assignable to type 'HelperCond<I, string, T | undefined, RegExp, SettingComposedValue<T>[]>'. - } - - if (_.isRegExp(_id)) { - return Object.keys(Meteor.settings).reduce((/** @type {SettingComposedValue<T>[]} */ items, key) => { - const value = Meteor.settings[key]; - if (_id.test(key)) { - items.push({ key, value }); - } - return items; - }, []); // Ok - } - - return Meteor.settings?.[_id]; // Error - ~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2536: Type 'I' cannot be used to index type '{ [s: string]: any; }'. - } - } - - // File: Rocket.Chat/apps/meteor/app/ui-utils/client/lib/messageBox.ts - - /** - * @typedef {MyObj} MessageBoxAction - */ - - /** - * @template {string | undefined} T - * @param {T} group - * @returns {HelperCond<T, string, MessageBoxAction[], undefined, Record<string, MessageBoxAction[]>>} - */ - function getWithBug(group) { - if (!group) { - return /** @type {Record<string, MessageBoxAction[]>} */({}); // Error - ~~~~~~ -!!! error TS2322: Type 'Record<string, MyObj[]>' is not assignable to type 'HelperCond<T, string, MyObj[], undefined, Record<string, MyObj[]>>'. - } - return /** @type {MessageBoxAction[]} */([]); // Ok - } - - /** - * @template {string | undefined} T - * @param {T} group - * @returns {HelperCond<T, string, MessageBoxAction[], undefined, Record<string, MessageBoxAction[]>>} - */ - function getWithoutBug(group) { - if (group === undefined) { - return /** @type {Record<string, MessageBoxAction[]>} */({}); // Ok - } - return /** @type {MessageBoxAction[]} */([]); // Ok - } - - // File: Rocket.Chat/apps/meteor/ee/server/lib/engagementDashboard/date.ts - - /** - * @param {string} x - * @returns {Date} - */ - function mapDateForAPI(x) { - return /** @type {any} */ (undefined); - } - - /** - * @template {string | undefined} T - * @param {string} start - * @param {T} [end] - * @returns {HelperCond<T, string, { start: Date, end: Date }, undefined, { start: Date, end: undefined }>} - */ - function transformDatesForAPI(start, end) { - return end !== undefined ? - { - start: mapDateForAPI(start), - end: mapDateForAPI(end), - } : - { - start: mapDateForAPI(start), - end: undefined - }; - } - - // File: Rocket.Chat/packages/agenda/src/Agenda.ts - - /** - * @typedef {MyObj} RepeatOptions - */ - - /** - * @typedef {MyObj} Job - */ - - /** - * @typedef {Object} IJob - * @property {MyObj} data - */ - class NewAgenda { - /** - * @param {string | number} interval - * @param {string} name - * @param {IJob['data']} data - * @param {RepeatOptions} options - * @returns {Promise<Job>} - */ - async _createIntervalJob(interval, name, data, options) { - return /** @type {any} */ (undefined); - } - - /** - * @param {string | number} interval - * @param {string[]} names - * @param {IJob['data']} data - * @param {RepeatOptions} options - * @returns {Promise<Job[]> | undefined} - */ - _createIntervalJobs(interval, names, data, options) { - return undefined; - } - - /** - * @template {string | string[]} T - * @param {string | number} interval - * @param {T} name - * @param {IJob['data']} data - * @param {RepeatOptions} options - * @returns {Promise<HelperCond<T, string, Job, string[], Job[] | undefined>>} - */ - async newEvery(interval, name, data, options) { - if (typeof name === 'string') { - return this._createIntervalJob(interval, name, data, options); // Ok - } - - if (Array.isArray(name)) { - return this._createIntervalJobs(interval, name, data, options); // Ok - } - - throw new Error('Unexpected error: Invalid job name(s)'); - } - } - - // File: angular/packages/common/src/pipes/case_conversion_pipes.ts - - /** - * @template {string | null | undefined} T - * @param {T} value - * @returns {HelperCond<T, string, string, null | undefined, null>} - */ - function transform1(value) { - if (value == null) return null; // Ok - if (typeof value !== 'string') { - throw new Error(); - } - return value.toLowerCase(); // Ok - } - \ No newline at end of file diff --git a/tests/baselines/reference/dependentReturnType2.symbols b/tests/baselines/reference/dependentReturnType2.symbols deleted file mode 100644 index 4b41f3fe744db..0000000000000 --- a/tests/baselines/reference/dependentReturnType2.symbols +++ /dev/null @@ -1,594 +0,0 @@ -//// [tests/cases/compiler/dependentReturnType2.ts] //// - -=== file.js === -// Adapted from ts-error-deltas repos - -/** - * @template T - * @template A - * @template R1 - * @template B - * @template R2 - * @typedef {T extends A ? R1 : T extends B ? R2 : never} HelperCond - */ - -/** - * @typedef IMessage - * @property {string} [html] - * @property {Object[]} [tokens] - */ - -class NewKatex { ->NewKatex : Symbol(NewKatex, Decl(file.js, 0, 0)) - - /** - * @param {string} s - * @returns {string} - */ - render(s) { ->render : Symbol(NewKatex.render, Decl(file.js, 17, 16)) ->s : Symbol(s, Decl(file.js, 22, 11)) - - return ""; - } - - /** - * @template {string | IMessage} T - * @param {T} message - * @returns {T extends string ? string : T extends IMessage ? IMessage : never} - */ - renderMessage(message) { ->renderMessage : Symbol(NewKatex.renderMessage, Decl(file.js, 24, 5)) ->message : Symbol(message, Decl(file.js, 31, 18)) - - if (typeof message === 'string') { ->message : Symbol(message, Decl(file.js, 31, 18)) - - return this.render(message); // Ok ->this.render : Symbol(NewKatex.render, Decl(file.js, 17, 16)) ->this : Symbol(NewKatex, Decl(file.js, 0, 0)) ->render : Symbol(NewKatex.render, Decl(file.js, 17, 16)) ->message : Symbol(message, Decl(file.js, 31, 18)) - } - - if (!message.html?.trim()) { ->message.html?.trim : Symbol(String.trim, Decl(lib.es5.d.ts, --, --)) ->message.html : Symbol(html, Decl(file.js, 13, 3)) ->message : Symbol(message, Decl(file.js, 31, 18)) ->html : Symbol(html, Decl(file.js, 13, 3)) ->trim : Symbol(String.trim, Decl(lib.es5.d.ts, --, --)) - - return message; // Ok ->message : Symbol(message, Decl(file.js, 31, 18)) - } - - if (!message.tokens) { ->message.tokens : Symbol(tokens, Decl(file.js, 14, 3)) ->message : Symbol(message, Decl(file.js, 31, 18)) ->tokens : Symbol(tokens, Decl(file.js, 14, 3)) - - message.tokens = []; ->message.tokens : Symbol(tokens, Decl(file.js, 14, 3)) ->message : Symbol(message, Decl(file.js, 31, 18)) ->tokens : Symbol(tokens, Decl(file.js, 14, 3)) - } - - message.html = this.render(message.html); ->message.html : Symbol(html, Decl(file.js, 13, 3)) ->message : Symbol(message, Decl(file.js, 31, 18)) ->html : Symbol(html, Decl(file.js, 13, 3)) ->this.render : Symbol(NewKatex.render, Decl(file.js, 17, 16)) ->this : Symbol(NewKatex, Decl(file.js, 0, 0)) ->render : Symbol(NewKatex.render, Decl(file.js, 17, 16)) ->message.html : Symbol(html, Decl(file.js, 13, 3)) ->message : Symbol(message, Decl(file.js, 31, 18)) ->html : Symbol(html, Decl(file.js, 13, 3)) - - return message; // Ok ->message : Symbol(message, Decl(file.js, 31, 18)) - } -} - -/** - * @template {true | false} T - * @param {{ dollarSyntax: boolean; parenthesisSyntax: boolean; }} options - * @param {T} _isMessage - * @returns {T extends true ? (message: IMessage) => IMessage : T extends false ? (message: string) => string : never} - */ -function createKatexMessageRendering(options, _isMessage) { ->createKatexMessageRendering : Symbol(createKatexMessageRendering, Decl(file.js, 47, 1)) ->options : Symbol(options, Decl(file.js, 55, 37)) ->_isMessage : Symbol(_isMessage, Decl(file.js, 55, 45)) - - const instance = new NewKatex(); ->instance : Symbol(instance, Decl(file.js, 56, 9)) ->NewKatex : Symbol(NewKatex, Decl(file.js, 0, 0)) - - if (_isMessage) { ->_isMessage : Symbol(_isMessage, Decl(file.js, 55, 45)) - - return (/** @type {IMessage} */ message) => instance.renderMessage(message); // Ok ->message : Symbol(message, Decl(file.js, 58, 16)) ->instance.renderMessage : Symbol(NewKatex.renderMessage, Decl(file.js, 24, 5)) ->instance : Symbol(instance, Decl(file.js, 56, 9)) ->renderMessage : Symbol(NewKatex.renderMessage, Decl(file.js, 24, 5)) ->message : Symbol(message, Decl(file.js, 58, 16)) - } - return (/** @type {string} */ message) => instance.renderMessage(message); // Ok ->message : Symbol(message, Decl(file.js, 60, 12)) ->instance.renderMessage : Symbol(NewKatex.renderMessage, Decl(file.js, 24, 5)) ->instance : Symbol(instance, Decl(file.js, 56, 9)) ->renderMessage : Symbol(NewKatex.renderMessage, Decl(file.js, 24, 5)) ->message : Symbol(message, Decl(file.js, 60, 12)) -} - -// File: Rocket.Chat/apps/meteor/app/settings/lib/settings.ts - -/** - * @typedef {Record<any, any>} MyObj - */ - - -/** - * @typedef {MyObj} SettingValue - */ - -/** - * @template {SettingValue} T - * @typedef {Object} SettingComposedValue - * @property {string} key - * @property {SettingValue} value - */ - -/** - * @callback SettingCallback - * @param {string} key - * @param {SettingValue} value - * @param {boolean} [initialLoad] - * @returns {void} - */ - -/** @type {{ settings: { [s: string]: any } }} */ -const Meteor = /** @type {any} */ (undefined); ->Meteor : Symbol(Meteor, Decl(file.js, 90, 5)) ->undefined : Symbol(undefined) - -/** @type {{ isRegExp(x: unknown): x is RegExp; }} */ -const _ = /** @type {any} */ (undefined); ->_ : Symbol(_, Decl(file.js, 92, 5)) ->undefined : Symbol(undefined) - -/** - * @param {RegExp} x - * @returns {void} - */ -function takesRegExp(x) { ->takesRegExp : Symbol(takesRegExp, Decl(file.js, 92, 41)) ->x : Symbol(x, Decl(file.js, 98, 21)) - - return /** @type {any} */ undefined; ->undefined : Symbol(undefined) -} -/** - * @param {string} x - * @returns {void} - */ -function takesString(x) { ->takesString : Symbol(takesString, Decl(file.js, 100, 1)) ->x : Symbol(x, Decl(file.js, 105, 21)) - - return /** @type {any} */ undefined; ->undefined : Symbol(undefined) -} - -/** - * @class NewSettingsBase - */ -class NewSettingsBase { ->NewSettingsBase : Symbol(NewSettingsBase, Decl(file.js, 107, 1)) - - /** - * @template {SettingCallback | undefined} C - * @template {string | RegExp} I - * @template {SettingValue} T - * @param {I} _id - * @param {C} [callback] - * @returns {HelperCond<C, SettingCallback, void, undefined, HelperCond<I, string, T | undefined, RegExp, SettingComposedValue<T>[]>>} - */ - newGet(_id, callback) { ->newGet : Symbol(NewSettingsBase.newGet, Decl(file.js, 112, 23)) ->_id : Symbol(_id, Decl(file.js, 121, 11)) ->callback : Symbol(callback, Decl(file.js, 121, 15)) - - if (callback !== undefined) { ->callback : Symbol(callback, Decl(file.js, 121, 15)) ->undefined : Symbol(undefined) - - if (!Meteor.settings) { ->Meteor.settings : Symbol(settings, Decl(file.js, 89, 12)) ->Meteor : Symbol(Meteor, Decl(file.js, 90, 5)) ->settings : Symbol(settings, Decl(file.js, 89, 12)) - - return; // Ok - } - if (_id === '*') { ->_id : Symbol(_id, Decl(file.js, 121, 11)) - - return Object.keys(Meteor.settings).forEach((key) => { ->Object.keys(Meteor.settings).forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --)) ->Object.keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) ->Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) ->keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) ->Meteor.settings : Symbol(settings, Decl(file.js, 89, 12)) ->Meteor : Symbol(Meteor, Decl(file.js, 90, 5)) ->settings : Symbol(settings, Decl(file.js, 89, 12)) ->forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --)) ->key : Symbol(key, Decl(file.js, 127, 61)) - - const value = Meteor.settings[key]; ->value : Symbol(value, Decl(file.js, 128, 25)) ->Meteor.settings : Symbol(settings, Decl(file.js, 89, 12)) ->Meteor : Symbol(Meteor, Decl(file.js, 90, 5)) ->settings : Symbol(settings, Decl(file.js, 89, 12)) ->key : Symbol(key, Decl(file.js, 127, 61)) - - callback(key, value); ->callback : Symbol(callback, Decl(file.js, 121, 15)) ->key : Symbol(key, Decl(file.js, 127, 61)) ->value : Symbol(value, Decl(file.js, 128, 25)) - - }); - } - if (_.isRegExp(_id) && Meteor.settings) { ->_.isRegExp : Symbol(isRegExp, Decl(file.js, 91, 12)) ->_ : Symbol(_, Decl(file.js, 92, 5)) ->isRegExp : Symbol(isRegExp, Decl(file.js, 91, 12)) ->_id : Symbol(_id, Decl(file.js, 121, 11)) ->Meteor.settings : Symbol(settings, Decl(file.js, 89, 12)) ->Meteor : Symbol(Meteor, Decl(file.js, 90, 5)) ->settings : Symbol(settings, Decl(file.js, 89, 12)) - - return Object.keys(Meteor.settings).forEach((key) => { ->Object.keys(Meteor.settings).forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --)) ->Object.keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) ->Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) ->keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) ->Meteor.settings : Symbol(settings, Decl(file.js, 89, 12)) ->Meteor : Symbol(Meteor, Decl(file.js, 90, 5)) ->settings : Symbol(settings, Decl(file.js, 89, 12)) ->forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --)) ->key : Symbol(key, Decl(file.js, 133, 61)) - - if (!_id.test(key)) { ->_id.test : Symbol(RegExp.test, Decl(lib.es5.d.ts, --, --)) ->_id : Symbol(_id, Decl(file.js, 121, 11)) ->test : Symbol(RegExp.test, Decl(lib.es5.d.ts, --, --)) ->key : Symbol(key, Decl(file.js, 133, 61)) - - return; - } - const value = Meteor.settings[key]; ->value : Symbol(value, Decl(file.js, 137, 25)) ->Meteor.settings : Symbol(settings, Decl(file.js, 89, 12)) ->Meteor : Symbol(Meteor, Decl(file.js, 90, 5)) ->settings : Symbol(settings, Decl(file.js, 89, 12)) ->key : Symbol(key, Decl(file.js, 133, 61)) - - callback(key, value); ->callback : Symbol(callback, Decl(file.js, 121, 15)) ->key : Symbol(key, Decl(file.js, 133, 61)) ->value : Symbol(value, Decl(file.js, 137, 25)) - - }); - } - - if (typeof _id === 'string') { ->_id : Symbol(_id, Decl(file.js, 121, 11)) - - const value = Meteor.settings[_id]; ->value : Symbol(value, Decl(file.js, 143, 21)) ->Meteor.settings : Symbol(settings, Decl(file.js, 89, 12)) ->Meteor : Symbol(Meteor, Decl(file.js, 90, 5)) ->settings : Symbol(settings, Decl(file.js, 89, 12)) ->_id : Symbol(_id, Decl(file.js, 121, 11)) - - if (value != null) { ->value : Symbol(value, Decl(file.js, 143, 21)) - - callback(_id, Meteor.settings[_id]); ->callback : Symbol(callback, Decl(file.js, 121, 15)) ->_id : Symbol(_id, Decl(file.js, 121, 11)) ->Meteor.settings : Symbol(settings, Decl(file.js, 89, 12)) ->Meteor : Symbol(Meteor, Decl(file.js, 90, 5)) ->settings : Symbol(settings, Decl(file.js, 89, 12)) ->_id : Symbol(_id, Decl(file.js, 121, 11)) - } - return; // Ok - } - - return; // Ok, needed for exhaustiveness check - } - - if (!Meteor.settings) { ->Meteor.settings : Symbol(settings, Decl(file.js, 89, 12)) ->Meteor : Symbol(Meteor, Decl(file.js, 90, 5)) ->settings : Symbol(settings, Decl(file.js, 89, 12)) - - return undefined; // Error ->undefined : Symbol(undefined) - } - - if (_.isRegExp(_id)) { ->_.isRegExp : Symbol(isRegExp, Decl(file.js, 91, 12)) ->_ : Symbol(_, Decl(file.js, 92, 5)) ->isRegExp : Symbol(isRegExp, Decl(file.js, 91, 12)) ->_id : Symbol(_id, Decl(file.js, 121, 11)) - - return Object.keys(Meteor.settings).reduce((/** @type {SettingComposedValue<T>[]} */ items, key) => { ->Object.keys(Meteor.settings).reduce : Symbol(Array.reduce, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) ->Object.keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) ->Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) ->keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) ->Meteor.settings : Symbol(settings, Decl(file.js, 89, 12)) ->Meteor : Symbol(Meteor, Decl(file.js, 90, 5)) ->settings : Symbol(settings, Decl(file.js, 89, 12)) ->reduce : Symbol(Array.reduce, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) ->items : Symbol(items, Decl(file.js, 158, 56)) ->key : Symbol(key, Decl(file.js, 158, 103)) - - const value = Meteor.settings[key]; ->value : Symbol(value, Decl(file.js, 159, 21)) ->Meteor.settings : Symbol(settings, Decl(file.js, 89, 12)) ->Meteor : Symbol(Meteor, Decl(file.js, 90, 5)) ->settings : Symbol(settings, Decl(file.js, 89, 12)) ->key : Symbol(key, Decl(file.js, 158, 103)) - - if (_id.test(key)) { ->_id.test : Symbol(RegExp.test, Decl(lib.es5.d.ts, --, --)) ->_id : Symbol(_id, Decl(file.js, 121, 11)) ->test : Symbol(RegExp.test, Decl(lib.es5.d.ts, --, --)) ->key : Symbol(key, Decl(file.js, 158, 103)) - - items.push({ key, value }); ->items.push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --)) ->items : Symbol(items, Decl(file.js, 158, 56)) ->push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --)) ->key : Symbol(key, Decl(file.js, 161, 32)) ->value : Symbol(value, Decl(file.js, 161, 37)) - } - return items; ->items : Symbol(items, Decl(file.js, 158, 56)) - - }, []); // Ok - } - - return Meteor.settings?.[_id]; // Error ->Meteor.settings : Symbol(settings, Decl(file.js, 89, 12)) ->Meteor : Symbol(Meteor, Decl(file.js, 90, 5)) ->settings : Symbol(settings, Decl(file.js, 89, 12)) ->_id : Symbol(_id, Decl(file.js, 121, 11)) - } -} - -// File: Rocket.Chat/apps/meteor/app/ui-utils/client/lib/messageBox.ts - -/** - * @typedef {MyObj} MessageBoxAction - */ - -/** - * @template {string | undefined} T - * @param {T} group - * @returns {HelperCond<T, string, MessageBoxAction[], undefined, Record<string, MessageBoxAction[]>>} - */ -function getWithBug(group) { ->getWithBug : Symbol(getWithBug, Decl(file.js, 169, 1)) ->group : Symbol(group, Decl(file.js, 182, 20)) - - if (!group) { ->group : Symbol(group, Decl(file.js, 182, 20)) - - return /** @type {Record<string, MessageBoxAction[]>} */({}); // Error - } - return /** @type {MessageBoxAction[]} */([]); // Ok -} - -/** - * @template {string | undefined} T - * @param {T} group - * @returns {HelperCond<T, string, MessageBoxAction[], undefined, Record<string, MessageBoxAction[]>>} - */ -function getWithoutBug(group) { ->getWithoutBug : Symbol(getWithoutBug, Decl(file.js, 187, 1)) ->group : Symbol(group, Decl(file.js, 194, 23)) - - if (group === undefined) { ->group : Symbol(group, Decl(file.js, 194, 23)) ->undefined : Symbol(undefined) - - return /** @type {Record<string, MessageBoxAction[]>} */({}); // Ok - } - return /** @type {MessageBoxAction[]} */([]); // Ok -} - -// File: Rocket.Chat/apps/meteor/ee/server/lib/engagementDashboard/date.ts - -/** - * @param {string} x - * @returns {Date} - */ -function mapDateForAPI(x) { ->mapDateForAPI : Symbol(mapDateForAPI, Decl(file.js, 199, 1)) ->x : Symbol(x, Decl(file.js, 207, 23)) - - return /** @type {any} */ (undefined); ->undefined : Symbol(undefined) -} - -/** - * @template {string | undefined} T - * @param {string} start - * @param {T} [end] - * @returns {HelperCond<T, string, { start: Date, end: Date }, undefined, { start: Date, end: undefined }>} - */ -function transformDatesForAPI(start, end) { ->transformDatesForAPI : Symbol(transformDatesForAPI, Decl(file.js, 209, 1)) ->start : Symbol(start, Decl(file.js, 217, 30)) ->end : Symbol(end, Decl(file.js, 217, 36)) - - return end !== undefined ? ->end : Symbol(end, Decl(file.js, 217, 36)) ->undefined : Symbol(undefined) - { - start: mapDateForAPI(start), ->start : Symbol(start, Decl(file.js, 219, 9)) ->mapDateForAPI : Symbol(mapDateForAPI, Decl(file.js, 199, 1)) ->start : Symbol(start, Decl(file.js, 217, 30)) - - end: mapDateForAPI(end), ->end : Symbol(end, Decl(file.js, 220, 40)) ->mapDateForAPI : Symbol(mapDateForAPI, Decl(file.js, 199, 1)) ->end : Symbol(end, Decl(file.js, 217, 36)) - - } : - { - start: mapDateForAPI(start), ->start : Symbol(start, Decl(file.js, 223, 9)) ->mapDateForAPI : Symbol(mapDateForAPI, Decl(file.js, 199, 1)) ->start : Symbol(start, Decl(file.js, 217, 30)) - - end: undefined ->end : Symbol(end, Decl(file.js, 224, 40)) ->undefined : Symbol(undefined) - - }; -} - -// File: Rocket.Chat/packages/agenda/src/Agenda.ts - -/** - * @typedef {MyObj} RepeatOptions - */ - -/** - * @typedef {MyObj} Job - */ - -/** - * @typedef {Object} IJob - * @property {MyObj} data - */ -class NewAgenda { ->NewAgenda : Symbol(NewAgenda, Decl(file.js, 227, 1)) - - /** - * @param {string | number} interval - * @param {string} name - * @param {IJob['data']} data - * @param {RepeatOptions} options - * @returns {Promise<Job>} - */ - async _createIntervalJob(interval, name, data, options) { ->_createIntervalJob : Symbol(NewAgenda._createIntervalJob, Decl(file.js, 243, 17)) ->interval : Symbol(interval, Decl(file.js, 251, 29)) ->name : Symbol(name, Decl(file.js, 251, 38)) ->data : Symbol(data, Decl(file.js, 251, 44)) ->options : Symbol(options, Decl(file.js, 251, 50)) - - return /** @type {any} */ (undefined); ->undefined : Symbol(undefined) - } - - /** - * @param {string | number} interval - * @param {string[]} names - * @param {IJob['data']} data - * @param {RepeatOptions} options - * @returns {Promise<Job[]> | undefined} - */ - _createIntervalJobs(interval, names, data, options) { ->_createIntervalJobs : Symbol(NewAgenda._createIntervalJobs, Decl(file.js, 253, 5)) ->interval : Symbol(interval, Decl(file.js, 262, 24)) ->names : Symbol(names, Decl(file.js, 262, 33)) ->data : Symbol(data, Decl(file.js, 262, 40)) ->options : Symbol(options, Decl(file.js, 262, 46)) - - return undefined; ->undefined : Symbol(undefined) - } - - /** - * @template {string | string[]} T - * @param {string | number} interval - * @param {T} name - * @param {IJob['data']} data - * @param {RepeatOptions} options - * @returns {Promise<HelperCond<T, string, Job, string[], Job[] | undefined>>} - */ - async newEvery(interval, name, data, options) { ->newEvery : Symbol(NewAgenda.newEvery, Decl(file.js, 264, 5)) ->interval : Symbol(interval, Decl(file.js, 274, 19)) ->name : Symbol(name, Decl(file.js, 274, 28)) ->data : Symbol(data, Decl(file.js, 274, 34)) ->options : Symbol(options, Decl(file.js, 274, 40)) - - if (typeof name === 'string') { ->name : Symbol(name, Decl(file.js, 274, 28)) - - return this._createIntervalJob(interval, name, data, options); // Ok ->this._createIntervalJob : Symbol(NewAgenda._createIntervalJob, Decl(file.js, 243, 17)) ->this : Symbol(NewAgenda, Decl(file.js, 227, 1)) ->_createIntervalJob : Symbol(NewAgenda._createIntervalJob, Decl(file.js, 243, 17)) ->interval : Symbol(interval, Decl(file.js, 274, 19)) ->name : Symbol(name, Decl(file.js, 274, 28)) ->data : Symbol(data, Decl(file.js, 274, 34)) ->options : Symbol(options, Decl(file.js, 274, 40)) - } - - if (Array.isArray(name)) { ->Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) ->Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 4 more) ->isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) ->name : Symbol(name, Decl(file.js, 274, 28)) - - return this._createIntervalJobs(interval, name, data, options); // Ok ->this._createIntervalJobs : Symbol(NewAgenda._createIntervalJobs, Decl(file.js, 253, 5)) ->this : Symbol(NewAgenda, Decl(file.js, 227, 1)) ->_createIntervalJobs : Symbol(NewAgenda._createIntervalJobs, Decl(file.js, 253, 5)) ->interval : Symbol(interval, Decl(file.js, 274, 19)) ->name : Symbol(name, Decl(file.js, 274, 28)) ->data : Symbol(data, Decl(file.js, 274, 34)) ->options : Symbol(options, Decl(file.js, 274, 40)) - } - - throw new Error('Unexpected error: Invalid job name(s)'); ->Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2022.error.d.ts, --, --)) - } -} - -// File: angular/packages/common/src/pipes/case_conversion_pipes.ts - -/** - * @template {string | null | undefined} T - * @param {T} value - * @returns {HelperCond<T, string, string, null | undefined, null>} - */ -function transform1(value) { ->transform1 : Symbol(transform1, Decl(file.js, 285, 1)) ->value : Symbol(value, Decl(file.js, 294, 20)) - - if (value == null) return null; // Ok ->value : Symbol(value, Decl(file.js, 294, 20)) - - if (typeof value !== 'string') { ->value : Symbol(value, Decl(file.js, 294, 20)) - - throw new Error(); ->Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2022.error.d.ts, --, --)) - } - return value.toLowerCase(); // Ok ->value.toLowerCase : Symbol(String.toLowerCase, Decl(lib.es5.d.ts, --, --)) ->value : Symbol(value, Decl(file.js, 294, 20)) ->toLowerCase : Symbol(String.toLowerCase, Decl(lib.es5.d.ts, --, --)) -} - diff --git a/tests/baselines/reference/dependentReturnType2.types b/tests/baselines/reference/dependentReturnType2.types deleted file mode 100644 index 1adf92c29a8fd..0000000000000 --- a/tests/baselines/reference/dependentReturnType2.types +++ /dev/null @@ -1,1007 +0,0 @@ -//// [tests/cases/compiler/dependentReturnType2.ts] //// - -=== file.js === -// Adapted from ts-error-deltas repos - -/** - * @template T - * @template A - * @template R1 - * @template B - * @template R2 - * @typedef {T extends A ? R1 : T extends B ? R2 : never} HelperCond - */ - -/** - * @typedef IMessage - * @property {string} [html] - * @property {Object[]} [tokens] - */ - -class NewKatex { ->NewKatex : NewKatex -> : ^^^^^^^^ - - /** - * @param {string} s - * @returns {string} - */ - render(s) { ->render : (s: string) => string -> : ^ ^^ ^^^^^ ->s : string -> : ^^^^^^ - - return ""; ->"" : "" -> : ^^ - } - - /** - * @template {string | IMessage} T - * @param {T} message - * @returns {T extends string ? string : T extends IMessage ? IMessage : never} - */ - renderMessage(message) { ->renderMessage : <T extends string | IMessage>(message: T) => T extends string ? string : T extends IMessage ? IMessage : never -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->message : T -> : ^ - - if (typeof message === 'string') { ->typeof message === 'string' : boolean -> : ^^^^^^^ ->typeof message : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->message : T -> : ^ ->'string' : "string" -> : ^^^^^^^^ - - return this.render(message); // Ok ->this.render(message) : string -> : ^^^^^^ ->this.render : (s: string) => string -> : ^ ^^ ^^^^^ ->this : this -> : ^^^^ ->render : (s: string) => string -> : ^ ^^ ^^^^^ ->message : string -> : ^^^^^^ - } - - if (!message.html?.trim()) { ->!message.html?.trim() : boolean -> : ^^^^^^^ ->message.html?.trim() : string | undefined -> : ^^^^^^^^^^^^^^^^^^ ->message.html?.trim : (() => string) | undefined -> : ^^^^^^^ ^^^^^^^^^^^^^ ->message.html : string | undefined -> : ^^^^^^^^^^^^^^^^^^ ->message : IMessage -> : ^^^^^^^^ ->html : string | undefined -> : ^^^^^^^^^^^^^^^^^^ ->trim : (() => string) | undefined -> : ^^^^^^^ ^^^^^^^^^^^^^ - - return message; // Ok ->message : IMessage -> : ^^^^^^^^ - } - - if (!message.tokens) { ->!message.tokens : boolean -> : ^^^^^^^ ->message.tokens : Object[] | undefined -> : ^^^^^^^^^^^^^^^^^^^^ ->message : IMessage -> : ^^^^^^^^ ->tokens : Object[] | undefined -> : ^^^^^^^^^^^^^^^^^^^^ - - message.tokens = []; ->message.tokens = [] : never[] -> : ^^^^^^^ ->message.tokens : Object[] | undefined -> : ^^^^^^^^^^^^^^^^^^^^ ->message : IMessage -> : ^^^^^^^^ ->tokens : Object[] | undefined -> : ^^^^^^^^^^^^^^^^^^^^ ->[] : never[] -> : ^^^^^^^ - } - - message.html = this.render(message.html); ->message.html = this.render(message.html) : string -> : ^^^^^^ ->message.html : string | undefined -> : ^^^^^^^^^^^^^^^^^^ ->message : IMessage -> : ^^^^^^^^ ->html : string | undefined -> : ^^^^^^^^^^^^^^^^^^ ->this.render(message.html) : string -> : ^^^^^^ ->this.render : (s: string) => string -> : ^ ^^ ^^^^^ ->this : this -> : ^^^^ ->render : (s: string) => string -> : ^ ^^ ^^^^^ ->message.html : string -> : ^^^^^^ ->message : IMessage -> : ^^^^^^^^ ->html : string -> : ^^^^^^ - - return message; // Ok ->message : IMessage -> : ^^^^^^^^ - } -} - -/** - * @template {true | false} T - * @param {{ dollarSyntax: boolean; parenthesisSyntax: boolean; }} options - * @param {T} _isMessage - * @returns {T extends true ? (message: IMessage) => IMessage : T extends false ? (message: string) => string : never} - */ -function createKatexMessageRendering(options, _isMessage) { ->createKatexMessageRendering : <T extends true | false>(options: { dollarSyntax: boolean; parenthesisSyntax: boolean; }, _isMessage: T) => T extends true ? (message: IMessage) => IMessage : T extends false ? (message: string) => string : never -> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^ ->options : { dollarSyntax: boolean; parenthesisSyntax: boolean; } -> : ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^ ^^^ ->_isMessage : T -> : ^ - - const instance = new NewKatex(); ->instance : NewKatex -> : ^^^^^^^^ ->new NewKatex() : NewKatex -> : ^^^^^^^^ ->NewKatex : typeof NewKatex -> : ^^^^^^^^^^^^^^^ - - if (_isMessage) { ->_isMessage : T -> : ^ - - return (/** @type {IMessage} */ message) => instance.renderMessage(message); // Ok ->(/** @type {IMessage} */ message) => instance.renderMessage(message) : (message: IMessage) => IMessage -> : ^ ^^ ^^^^^^^^^^^^^ ->message : IMessage -> : ^^^^^^^^ ->instance.renderMessage(message) : IMessage -> : ^^^^^^^^ ->instance.renderMessage : <T_1 extends string | IMessage>(message: T_1) => T_1 extends string ? string : T_1 extends IMessage ? IMessage : never -> : ^^^^^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->instance : NewKatex -> : ^^^^^^^^ ->renderMessage : <T_1 extends string | IMessage>(message: T_1) => T_1 extends string ? string : T_1 extends IMessage ? IMessage : never -> : ^^^^^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->message : IMessage -> : ^^^^^^^^ - } - return (/** @type {string} */ message) => instance.renderMessage(message); // Ok ->(/** @type {string} */ message) => instance.renderMessage(message) : (message: string) => string -> : ^ ^^ ^^^^^^^^^^^ ->message : string -> : ^^^^^^ ->instance.renderMessage(message) : string -> : ^^^^^^ ->instance.renderMessage : <T_1 extends string | IMessage>(message: T_1) => T_1 extends string ? string : T_1 extends IMessage ? IMessage : never -> : ^^^^^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->instance : NewKatex -> : ^^^^^^^^ ->renderMessage : <T_1 extends string | IMessage>(message: T_1) => T_1 extends string ? string : T_1 extends IMessage ? IMessage : never -> : ^^^^^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->message : string -> : ^^^^^^ -} - -// File: Rocket.Chat/apps/meteor/app/settings/lib/settings.ts - -/** - * @typedef {Record<any, any>} MyObj - */ - - -/** - * @typedef {MyObj} SettingValue - */ - -/** - * @template {SettingValue} T - * @typedef {Object} SettingComposedValue - * @property {string} key - * @property {SettingValue} value - */ - -/** - * @callback SettingCallback - * @param {string} key - * @param {SettingValue} value - * @param {boolean} [initialLoad] - * @returns {void} - */ - -/** @type {{ settings: { [s: string]: any } }} */ -const Meteor = /** @type {any} */ (undefined); ->Meteor : { settings: { [s: string]: any; }; } -> : ^^^^^^^^^^^^ ^^^ ->(undefined) : any -> : ^^^ ->undefined : undefined -> : ^^^^^^^^^ - -/** @type {{ isRegExp(x: unknown): x is RegExp; }} */ -const _ = /** @type {any} */ (undefined); ->_ : { isRegExp(x: unknown): x is RegExp; } -> : ^^^^^^^^^^^ ^^ ^^^ ^^^ ->(undefined) : any -> : ^^^ ->undefined : undefined -> : ^^^^^^^^^ - -/** - * @param {RegExp} x - * @returns {void} - */ -function takesRegExp(x) { ->takesRegExp : (x: RegExp) => void -> : ^ ^^ ^^^^^ ->x : RegExp -> : ^^^^^^ - - return /** @type {any} */ undefined; ->undefined : undefined -> : ^^^^^^^^^ -} -/** - * @param {string} x - * @returns {void} - */ -function takesString(x) { ->takesString : (x: string) => void -> : ^ ^^ ^^^^^ ->x : string -> : ^^^^^^ - - return /** @type {any} */ undefined; ->undefined : undefined -> : ^^^^^^^^^ -} - -/** - * @class NewSettingsBase - */ -class NewSettingsBase { ->NewSettingsBase : NewSettingsBase -> : ^^^^^^^^^^^^^^^ - - /** - * @template {SettingCallback | undefined} C - * @template {string | RegExp} I - * @template {SettingValue} T - * @param {I} _id - * @param {C} [callback] - * @returns {HelperCond<C, SettingCallback, void, undefined, HelperCond<I, string, T | undefined, RegExp, SettingComposedValue<T>[]>>} - */ - newGet(_id, callback) { ->newGet : <C extends SettingCallback | undefined, I extends string | RegExp, T extends SettingValue>(_id: I, callback?: C) => HelperCond<C, SettingCallback, void, undefined, HelperCond<I, string, T | undefined, RegExp, SettingComposedValue<T>[]>> -> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^^ ^^^^^ ->_id : I -> : ^ ->callback : C | undefined -> : ^^^^^^^^^^^^^ - - if (callback !== undefined) { ->callback !== undefined : boolean -> : ^^^^^^^ ->callback : C | undefined -> : ^^^^^^^^^^^^^ ->undefined : undefined -> : ^^^^^^^^^ - - if (!Meteor.settings) { ->!Meteor.settings : false -> : ^^^^^ ->Meteor.settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->Meteor : { settings: { [s: string]: any; }; } -> : ^^^^^^^^^^^^ ^^^ ->settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ - - return; // Ok - } - if (_id === '*') { ->_id === '*' : boolean -> : ^^^^^^^ ->_id : I -> : ^ ->'*' : "*" -> : ^^^ - - return Object.keys(Meteor.settings).forEach((key) => { ->Object.keys(Meteor.settings).forEach((key) => { const value = Meteor.settings[key]; callback(key, value); }) : void -> : ^^^^ ->Object.keys(Meteor.settings).forEach : (callbackfn: (value: string, index: number, array: string[]) => void, thisArg?: any) => void -> : ^ ^^^ ^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^ ^^ ^^^ ^^^^^ ->Object.keys(Meteor.settings) : string[] -> : ^^^^^^^^ ->Object.keys : { (o: object): string[]; (o: {}): string[]; } -> : ^^^ ^^ ^^^ ^^^ ^^ ^^^ ^^^ ->Object : ObjectConstructor -> : ^^^^^^^^^^^^^^^^^ ->keys : { (o: object): string[]; (o: {}): string[]; } -> : ^^^ ^^ ^^^ ^^^ ^^ ^^^ ^^^ ->Meteor.settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->Meteor : { settings: { [s: string]: any; }; } -> : ^^^^^^^^^^^^ ^^^ ->settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->forEach : (callbackfn: (value: string, index: number, array: string[]) => void, thisArg?: any) => void -> : ^ ^^^ ^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^ ^^ ^^^ ^^^^^ ->(key) => { const value = Meteor.settings[key]; callback(key, value); } : (key: string) => void -> : ^ ^^^^^^^^^^^^^^^^^ ->key : string -> : ^^^^^^ - - const value = Meteor.settings[key]; ->value : any -> : ^^^ ->Meteor.settings[key] : any -> : ^^^ ->Meteor.settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->Meteor : { settings: { [s: string]: any; }; } -> : ^^^^^^^^^^^^ ^^^ ->settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->key : string -> : ^^^^^^ - - callback(key, value); ->callback(key, value) : void -> : ^^^^ ->callback : SettingCallback -> : ^^^^^^^^^^^^^^^ ->key : string -> : ^^^^^^ ->value : any -> : ^^^ - - }); - } - if (_.isRegExp(_id) && Meteor.settings) { ->_.isRegExp(_id) && Meteor.settings : false | { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->_.isRegExp(_id) : boolean -> : ^^^^^^^ ->_.isRegExp : (x: unknown) => x is RegExp -> : ^ ^^ ^^^^^ ->_ : { isRegExp(x: unknown): x is RegExp; } -> : ^^^^^^^^^^^ ^^ ^^^ ^^^ ->isRegExp : (x: unknown) => x is RegExp -> : ^ ^^ ^^^^^ ->_id : string | RegExp -> : ^^^^^^^^^^^^^^^ ->Meteor.settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->Meteor : { settings: { [s: string]: any; }; } -> : ^^^^^^^^^^^^ ^^^ ->settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ - - return Object.keys(Meteor.settings).forEach((key) => { ->Object.keys(Meteor.settings).forEach((key) => { if (!_id.test(key)) { return; } const value = Meteor.settings[key]; callback(key, value); }) : void -> : ^^^^ ->Object.keys(Meteor.settings).forEach : (callbackfn: (value: string, index: number, array: string[]) => void, thisArg?: any) => void -> : ^ ^^^ ^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^ ^^ ^^^ ^^^^^ ->Object.keys(Meteor.settings) : string[] -> : ^^^^^^^^ ->Object.keys : { (o: object): string[]; (o: {}): string[]; } -> : ^^^ ^^ ^^^ ^^^ ^^ ^^^ ^^^ ->Object : ObjectConstructor -> : ^^^^^^^^^^^^^^^^^ ->keys : { (o: object): string[]; (o: {}): string[]; } -> : ^^^ ^^ ^^^ ^^^ ^^ ^^^ ^^^ ->Meteor.settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->Meteor : { settings: { [s: string]: any; }; } -> : ^^^^^^^^^^^^ ^^^ ->settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->forEach : (callbackfn: (value: string, index: number, array: string[]) => void, thisArg?: any) => void -> : ^ ^^^ ^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^ ^^ ^^^ ^^^^^ ->(key) => { if (!_id.test(key)) { return; } const value = Meteor.settings[key]; callback(key, value); } : (key: string) => void -> : ^ ^^^^^^^^^^^^^^^^^ ->key : string -> : ^^^^^^ - - if (!_id.test(key)) { ->!_id.test(key) : boolean -> : ^^^^^^^ ->_id.test(key) : boolean -> : ^^^^^^^ ->_id.test : (string: string) => boolean -> : ^ ^^ ^^^^^ ->_id : RegExp -> : ^^^^^^ ->test : (string: string) => boolean -> : ^ ^^ ^^^^^ ->key : string -> : ^^^^^^ - - return; - } - const value = Meteor.settings[key]; ->value : any -> : ^^^ ->Meteor.settings[key] : any -> : ^^^ ->Meteor.settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->Meteor : { settings: { [s: string]: any; }; } -> : ^^^^^^^^^^^^ ^^^ ->settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->key : string -> : ^^^^^^ - - callback(key, value); ->callback(key, value) : void -> : ^^^^ ->callback : SettingCallback -> : ^^^^^^^^^^^^^^^ ->key : string -> : ^^^^^^ ->value : any -> : ^^^ - - }); - } - - if (typeof _id === 'string') { ->typeof _id === 'string' : boolean -> : ^^^^^^^ ->typeof _id : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->_id : I -> : ^ ->'string' : "string" -> : ^^^^^^^^ - - const value = Meteor.settings[_id]; ->value : any -> : ^^^ ->Meteor.settings[_id] : any -> : ^^^ ->Meteor.settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->Meteor : { settings: { [s: string]: any; }; } -> : ^^^^^^^^^^^^ ^^^ ->settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->_id : I & string -> : ^^^^^^^^^^ - - if (value != null) { ->value != null : boolean -> : ^^^^^^^ ->value : any -> : ^^^ - - callback(_id, Meteor.settings[_id]); ->callback(_id, Meteor.settings[_id]) : void -> : ^^^^ ->callback : SettingCallback -> : ^^^^^^^^^^^^^^^ ->_id : string -> : ^^^^^^ ->Meteor.settings[_id] : any -> : ^^^ ->Meteor.settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->Meteor : { settings: { [s: string]: any; }; } -> : ^^^^^^^^^^^^ ^^^ ->settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->_id : I & string -> : ^^^^^^^^^^ - } - return; // Ok - } - - return; // Ok, needed for exhaustiveness check - } - - if (!Meteor.settings) { ->!Meteor.settings : false -> : ^^^^^ ->Meteor.settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->Meteor : { settings: { [s: string]: any; }; } -> : ^^^^^^^^^^^^ ^^^ ->settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ - - return undefined; // Error ->undefined : undefined -> : ^^^^^^^^^ - } - - if (_.isRegExp(_id)) { ->_.isRegExp(_id) : boolean -> : ^^^^^^^ ->_.isRegExp : (x: unknown) => x is RegExp -> : ^ ^^ ^^^^^ ->_ : { isRegExp(x: unknown): x is RegExp; } -> : ^^^^^^^^^^^ ^^ ^^^ ^^^ ->isRegExp : (x: unknown) => x is RegExp -> : ^ ^^ ^^^^^ ->_id : string | RegExp -> : ^^^^^^^^^^^^^^^ - - return Object.keys(Meteor.settings).reduce((/** @type {SettingComposedValue<T>[]} */ items, key) => { ->Object.keys(Meteor.settings).reduce((/** @type {SettingComposedValue<T>[]} */ items, key) => { const value = Meteor.settings[key]; if (_id.test(key)) { items.push({ key, value }); } return items; }, []) : SettingComposedValue<T>[] -> : ^^^^^^^^^^^^^^^^^^^^^^^^^ ->Object.keys(Meteor.settings).reduce : { (callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string): string; (callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string, initialValue: string): string; <U>(callbackfn: (previousValue: U, currentValue: string, currentIndex: number, array: string[]) => U, initialValue: U): U; } -> : ^^^ ^^^ ^^^^^^^^^^ ^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^^^ ^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^ ^^ ^^^ ^^^^^ ^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ->Object.keys(Meteor.settings) : string[] -> : ^^^^^^^^ ->Object.keys : { (o: object): string[]; (o: {}): string[]; } -> : ^^^ ^^ ^^^ ^^^ ^^ ^^^ ^^^ ->Object : ObjectConstructor -> : ^^^^^^^^^^^^^^^^^ ->keys : { (o: object): string[]; (o: {}): string[]; } -> : ^^^ ^^ ^^^ ^^^ ^^ ^^^ ^^^ ->Meteor.settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->Meteor : { settings: { [s: string]: any; }; } -> : ^^^^^^^^^^^^ ^^^ ->settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->reduce : { (callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string): string; (callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string, initialValue: string): string; <U>(callbackfn: (previousValue: U, currentValue: string, currentIndex: number, array: string[]) => U, initialValue: U): U; } -> : ^^^ ^^^ ^^^^^^^^^^ ^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^^^ ^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^ ^^ ^^^ ^^^^^ ^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ->(/** @type {SettingComposedValue<T>[]} */ items, key) => { const value = Meteor.settings[key]; if (_id.test(key)) { items.push({ key, value }); } return items; } : (items: SettingComposedValue<T>[], key: string) => SettingComposedValue<T>[] -> : ^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->items : SettingComposedValue<T>[] -> : ^^^^^^^^^^^^^^^^^^^^^^^^^ ->key : string -> : ^^^^^^ - - const value = Meteor.settings[key]; ->value : any -> : ^^^ ->Meteor.settings[key] : any -> : ^^^ ->Meteor.settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->Meteor : { settings: { [s: string]: any; }; } -> : ^^^^^^^^^^^^ ^^^ ->settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->key : string -> : ^^^^^^ - - if (_id.test(key)) { ->_id.test(key) : boolean -> : ^^^^^^^ ->_id.test : (string: string) => boolean -> : ^ ^^ ^^^^^ ->_id : RegExp -> : ^^^^^^ ->test : (string: string) => boolean -> : ^ ^^ ^^^^^ ->key : string -> : ^^^^^^ - - items.push({ key, value }); ->items.push({ key, value }) : number -> : ^^^^^^ ->items.push : (...items: SettingComposedValue<T>[]) => number -> : ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->items : SettingComposedValue<T>[] -> : ^^^^^^^^^^^^^^^^^^^^^^^^^ ->push : (...items: SettingComposedValue<T>[]) => number -> : ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->{ key, value } : { key: string; value: any; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->key : string -> : ^^^^^^ ->value : any -> : ^^^ - } - return items; ->items : SettingComposedValue<T>[] -> : ^^^^^^^^^^^^^^^^^^^^^^^^^ - - }, []); // Ok ->[] : never[] -> : ^^^^^^^ - } - - return Meteor.settings?.[_id]; // Error ->Meteor.settings?.[_id] : any -> : ^^^ ->Meteor.settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->Meteor : { settings: { [s: string]: any; }; } -> : ^^^^^^^^^^^^ ^^^ ->settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->_id : I -> : ^ - } -} - -// File: Rocket.Chat/apps/meteor/app/ui-utils/client/lib/messageBox.ts - -/** - * @typedef {MyObj} MessageBoxAction - */ - -/** - * @template {string | undefined} T - * @param {T} group - * @returns {HelperCond<T, string, MessageBoxAction[], undefined, Record<string, MessageBoxAction[]>>} - */ -function getWithBug(group) { ->getWithBug : <T extends string | undefined>(group: T) => HelperCond<T, string, MessageBoxAction[], undefined, Record<string, MessageBoxAction[]>> -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->group : T -> : ^ - - if (!group) { ->!group : boolean -> : ^^^^^^^ ->group : T -> : ^ - - return /** @type {Record<string, MessageBoxAction[]>} */({}); // Error ->({}) : Record<string, MyObj[]> -> : ^^^^^^^^^^^^^^^^^^^^^^^ ->{} : {} -> : ^^ - } - return /** @type {MessageBoxAction[]} */([]); // Ok ->([]) : MyObj[] -> : ^^^^^^^ ->[] : never[] -> : ^^^^^^^ -} - -/** - * @template {string | undefined} T - * @param {T} group - * @returns {HelperCond<T, string, MessageBoxAction[], undefined, Record<string, MessageBoxAction[]>>} - */ -function getWithoutBug(group) { ->getWithoutBug : <T extends string | undefined>(group: T) => HelperCond<T, string, MessageBoxAction[], undefined, Record<string, MessageBoxAction[]>> -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->group : T -> : ^ - - if (group === undefined) { ->group === undefined : boolean -> : ^^^^^^^ ->group : T -> : ^ ->undefined : undefined -> : ^^^^^^^^^ - - return /** @type {Record<string, MessageBoxAction[]>} */({}); // Ok ->({}) : Record<string, MyObj[]> -> : ^^^^^^^^^^^^^^^^^^^^^^^ ->{} : {} -> : ^^ - } - return /** @type {MessageBoxAction[]} */([]); // Ok ->([]) : MyObj[] -> : ^^^^^^^ ->[] : never[] -> : ^^^^^^^ -} - -// File: Rocket.Chat/apps/meteor/ee/server/lib/engagementDashboard/date.ts - -/** - * @param {string} x - * @returns {Date} - */ -function mapDateForAPI(x) { ->mapDateForAPI : (x: string) => Date -> : ^ ^^ ^^^^^ ->x : string -> : ^^^^^^ - - return /** @type {any} */ (undefined); ->(undefined) : any -> : ^^^ ->undefined : undefined -> : ^^^^^^^^^ -} - -/** - * @template {string | undefined} T - * @param {string} start - * @param {T} [end] - * @returns {HelperCond<T, string, { start: Date, end: Date }, undefined, { start: Date, end: undefined }>} - */ -function transformDatesForAPI(start, end) { ->transformDatesForAPI : <T extends string | undefined>(start: string, end?: T) => HelperCond<T, string, { start: Date; end: Date; }, undefined, { start: Date; end: undefined; }> -> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^^ ^^^^^ ->start : string -> : ^^^^^^ ->end : T | undefined -> : ^^^^^^^^^^^^^ - - return end !== undefined ? ->end !== undefined ? { start: mapDateForAPI(start), end: mapDateForAPI(end), } : { start: mapDateForAPI(start), end: undefined } : { start: Date; end: Date; } | { start: Date; end: undefined; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->end !== undefined : boolean -> : ^^^^^^^ ->end : T | undefined -> : ^^^^^^^^^^^^^ ->undefined : undefined -> : ^^^^^^^^^ - { ->{ start: mapDateForAPI(start), end: mapDateForAPI(end), } : { start: Date; end: Date; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - start: mapDateForAPI(start), ->start : Date -> : ^^^^ ->mapDateForAPI(start) : Date -> : ^^^^ ->mapDateForAPI : (x: string) => Date -> : ^ ^^ ^^^^^ ->start : string -> : ^^^^^^ - - end: mapDateForAPI(end), ->end : Date -> : ^^^^ ->mapDateForAPI(end) : Date -> : ^^^^ ->mapDateForAPI : (x: string) => Date -> : ^ ^^ ^^^^^ ->end : string -> : ^^^^^^ - - } : - { ->{ start: mapDateForAPI(start), end: undefined } : { start: Date; end: undefined; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - start: mapDateForAPI(start), ->start : Date -> : ^^^^ ->mapDateForAPI(start) : Date -> : ^^^^ ->mapDateForAPI : (x: string) => Date -> : ^ ^^ ^^^^^ ->start : string -> : ^^^^^^ - - end: undefined ->end : undefined -> : ^^^^^^^^^ ->undefined : undefined -> : ^^^^^^^^^ - - }; -} - -// File: Rocket.Chat/packages/agenda/src/Agenda.ts - -/** - * @typedef {MyObj} RepeatOptions - */ - -/** - * @typedef {MyObj} Job - */ - -/** - * @typedef {Object} IJob - * @property {MyObj} data - */ -class NewAgenda { ->NewAgenda : NewAgenda -> : ^^^^^^^^^ - - /** - * @param {string | number} interval - * @param {string} name - * @param {IJob['data']} data - * @param {RepeatOptions} options - * @returns {Promise<Job>} - */ - async _createIntervalJob(interval, name, data, options) { ->_createIntervalJob : (interval: string | number, name: string, data: IJob["data"], options: RepeatOptions) => Promise<Job> -> : ^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^ ->interval : string | number -> : ^^^^^^^^^^^^^^^ ->name : string -> : ^^^^^^ ->data : MyObj -> : ^^^^^ ->options : MyObj -> : ^^^^^ - - return /** @type {any} */ (undefined); ->(undefined) : any -> : ^^^ ->undefined : undefined -> : ^^^^^^^^^ - } - - /** - * @param {string | number} interval - * @param {string[]} names - * @param {IJob['data']} data - * @param {RepeatOptions} options - * @returns {Promise<Job[]> | undefined} - */ - _createIntervalJobs(interval, names, data, options) { ->_createIntervalJobs : (interval: string | number, names: string[], data: IJob["data"], options: RepeatOptions) => Promise<Job[]> | undefined -> : ^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^ ->interval : string | number -> : ^^^^^^^^^^^^^^^ ->names : string[] -> : ^^^^^^^^ ->data : MyObj -> : ^^^^^ ->options : MyObj -> : ^^^^^ - - return undefined; ->undefined : undefined -> : ^^^^^^^^^ - } - - /** - * @template {string | string[]} T - * @param {string | number} interval - * @param {T} name - * @param {IJob['data']} data - * @param {RepeatOptions} options - * @returns {Promise<HelperCond<T, string, Job, string[], Job[] | undefined>>} - */ - async newEvery(interval, name, data, options) { ->newEvery : <T extends string | string[]>(interval: string | number, name: T, data: IJob["data"], options: RepeatOptions) => Promise<HelperCond<T, string, Job, string[], Job[] | undefined>> -> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^ ->interval : string | number -> : ^^^^^^^^^^^^^^^ ->name : T -> : ^ ->data : MyObj -> : ^^^^^ ->options : MyObj -> : ^^^^^ - - if (typeof name === 'string') { ->typeof name === 'string' : boolean -> : ^^^^^^^ ->typeof name : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->name : T -> : ^ ->'string' : "string" -> : ^^^^^^^^ - - return this._createIntervalJob(interval, name, data, options); // Ok ->this._createIntervalJob(interval, name, data, options) : Promise<MyObj> -> : ^^^^^^^^^^^^^^ ->this._createIntervalJob : (interval: string | number, name: string, data: IJob["data"], options: RepeatOptions) => Promise<Job> -> : ^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^ ->this : this -> : ^^^^ ->_createIntervalJob : (interval: string | number, name: string, data: IJob["data"], options: RepeatOptions) => Promise<Job> -> : ^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^ ->interval : string | number -> : ^^^^^^^^^^^^^^^ ->name : string -> : ^^^^^^ ->data : MyObj -> : ^^^^^ ->options : MyObj -> : ^^^^^ - } - - if (Array.isArray(name)) { ->Array.isArray(name) : boolean -> : ^^^^^^^ ->Array.isArray : (arg: any) => arg is any[] -> : ^ ^^ ^^^^^ ->Array : ArrayConstructor -> : ^^^^^^^^^^^^^^^^ ->isArray : (arg: any) => arg is any[] -> : ^ ^^ ^^^^^ ->name : string[] -> : ^^^^^^^^ - - return this._createIntervalJobs(interval, name, data, options); // Ok ->this._createIntervalJobs(interval, name, data, options) : Promise<MyObj[]> | undefined -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->this._createIntervalJobs : (interval: string | number, names: string[], data: IJob["data"], options: RepeatOptions) => Promise<Job[]> | undefined -> : ^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^ ->this : this -> : ^^^^ ->_createIntervalJobs : (interval: string | number, names: string[], data: IJob["data"], options: RepeatOptions) => Promise<Job[]> | undefined -> : ^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^ ->interval : string | number -> : ^^^^^^^^^^^^^^^ ->name : string[] -> : ^^^^^^^^ ->data : MyObj -> : ^^^^^ ->options : MyObj -> : ^^^^^ - } - - throw new Error('Unexpected error: Invalid job name(s)'); ->new Error('Unexpected error: Invalid job name(s)') : Error -> : ^^^^^ ->Error : ErrorConstructor -> : ^^^^^^^^^^^^^^^^ ->'Unexpected error: Invalid job name(s)' : "Unexpected error: Invalid job name(s)" -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - } -} - -// File: angular/packages/common/src/pipes/case_conversion_pipes.ts - -/** - * @template {string | null | undefined} T - * @param {T} value - * @returns {HelperCond<T, string, string, null | undefined, null>} - */ -function transform1(value) { ->transform1 : <T extends string | null | undefined>(value: T) => HelperCond<T, string, string, null | undefined, null> -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->value : T -> : ^ - - if (value == null) return null; // Ok ->value == null : boolean -> : ^^^^^^^ ->value : T -> : ^ - - if (typeof value !== 'string') { ->typeof value !== 'string' : boolean -> : ^^^^^^^ ->typeof value : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->value : NonNullable<T> -> : ^^^^^^^^^^^^^^ ->'string' : "string" -> : ^^^^^^^^ - - throw new Error(); ->new Error() : Error -> : ^^^^^ ->Error : ErrorConstructor -> : ^^^^^^^^^^^^^^^^ - } - return value.toLowerCase(); // Ok ->value.toLowerCase() : string -> : ^^^^^^ ->value.toLowerCase : () => string -> : ^^^^^^ ->value : string -> : ^^^^^^ ->toLowerCase : () => string -> : ^^^^^^ -} - diff --git a/tests/baselines/reference/dependentReturnType3.errors.txt b/tests/baselines/reference/dependentReturnType3.errors.txt deleted file mode 100644 index 39a9326242262..0000000000000 --- a/tests/baselines/reference/dependentReturnType3.errors.txt +++ /dev/null @@ -1,224 +0,0 @@ -dependentReturnType3.ts(114,13): error TS2322: Type 'undefined' is not assignable to type 'HelperCond<I, string, T | undefined, RegExp, SettingComposedValue<T>[]>'. -dependentReturnType3.ts(130,16): error TS2536: Type 'I' cannot be used to index type '{ [s: string]: any; }'. -dependentReturnType3.ts(141,9): error TS2322: Type 'Record<string, object[]>' is not assignable to type 'HelperCond<T, string, object[], undefined, Record<string, object[]>>'. - - -==== dependentReturnType3.ts (3 errors) ==== - // Adapted from ts-error-deltas repos - - type HelperCond<T, A, R1, B, R2> = - T extends A - ? R1 - : T extends B - ? R2 - : never; - - - // File: Rocket.Chat/apps/meteor/app/katex/client/index.ts - interface IMessage { - html?: string; - tokens?: {}[]; - } - - class NewKatex { - render(s: string): string { - return ""; - } - - renderMessage<T extends string | IMessage>(message: T): - T extends string - ? string - : T extends IMessage - ? IMessage - : never { - if (typeof message === 'string') { - return this.render(message); // Ok - } - - if (!message.html?.trim()) { - return message; // Ok - } - - if (!message.tokens) { - message.tokens = []; - } - - message.html = this.render(message.html); - return message; // Ok - } - } - - export function createKatexMessageRendering<T extends true | false>( - options: { - dollarSyntax: boolean; - parenthesisSyntax: boolean; - }, - _isMessage: T, - ): T extends true - ? (message: IMessage) => IMessage - : T extends false - ? (message: string) => string - : never { - const instance = new NewKatex(); - if (_isMessage) { - return (message: IMessage): IMessage => instance.renderMessage(message); // Ok - } - return (message: string): string => instance.renderMessage(message); // Ok - } - - // File: Rocket.Chat/apps/meteor/app/settings/lib/settings.ts - type SettingComposedValue<T extends SettingValue = SettingValue> = { key: string; value: T }; - type SettingCallback = (key: string, value: SettingValue, initialLoad?: boolean) => void; - - type SettingValue = object; - declare const Meteor: { settings: { [s: string]: any } }; - declare const _: { isRegExp(x: unknown): x is RegExp; }; - declare function takesRegExp(x: RegExp): void; - declare function takesString(x: string): void; - - class NewSettingsBase { - public newGet<C extends SettingCallback | undefined, I extends string | RegExp, T extends SettingValue = SettingValue>( - _id: I, - callback?: C, - ): HelperCond<C, - SettingCallback, void, - undefined, HelperCond<I, - string, T | undefined, - RegExp, SettingComposedValue<T>[]>> { - if (callback !== undefined) { - if (!Meteor.settings) { - return; // Ok - } - if (_id === '*') { - return Object.keys(Meteor.settings).forEach((key) => { // Ok - const value = Meteor.settings[key]; - callback(key, value); - }); - } - if (_.isRegExp(_id) && Meteor.settings) { - return Object.keys(Meteor.settings).forEach((key) => { // Ok - if (!_id.test(key)) { - return; - } - const value = Meteor.settings[key]; - callback(key, value); - }); - } - - if (typeof _id === 'string') { - const value = Meteor.settings[_id]; - if (value != null) { - callback(_id, Meteor.settings[_id]); - } - return; // Ok - } - - return; // Ok, needed for exhaustiveness check - } - - if (!Meteor.settings) { // Wrong: we don't know that _id is string here, cannot return undefined - return undefined; // Error - ~~~~~~ -!!! error TS2322: Type 'undefined' is not assignable to type 'HelperCond<I, string, T | undefined, RegExp, SettingComposedValue<T>[]>'. - } - - if (_.isRegExp(_id)) { - return Object.keys(Meteor.settings).reduce((items: SettingComposedValue<T>[], key) => { - const value = Meteor.settings[key]; - if (_id.test(key)) { - items.push({ - key, - value, - }); - } - return items; - }, []); // Ok - } - - return Meteor.settings?.[_id]; // Error - ~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2536: Type 'I' cannot be used to index type '{ [s: string]: any; }'. - // The indexing currently doesn't work because it doesn't use the narrowed type of `_id`. - } - } - - // File: Rocket.Chat/apps/meteor/app/ui-utils/client/lib/messageBox.ts - type MessageBoxAction = object; - - function getWithBug<T extends string | undefined>(group: T): - HelperCond<T, string, MessageBoxAction[], undefined, Record<string, MessageBoxAction[]>> { - if (!group) { - return {} as Record<string, MessageBoxAction[]>; // Error, could fall into this branch when group is empty string - ~~~~~~ -!!! error TS2322: Type 'Record<string, object[]>' is not assignable to type 'HelperCond<T, string, object[], undefined, Record<string, object[]>>'. - } - - return [] as MessageBoxAction[]; // Ok - } - - function getWithoutBug<T extends string | undefined>(group: T): - HelperCond<T, string, MessageBoxAction[], undefined, Record<string, MessageBoxAction[]>> { - if (group === undefined) { - return {} as Record<string, MessageBoxAction[]>; // Ok - } - - return [] as MessageBoxAction[]; // Ok - } - - // File: Rocket.Chat/apps/meteor/ee/server/lib/engagementDashboard/date.ts - declare function mapDateForAPI(x: string): Date; - export function transformDatesForAPI<T extends string | undefined>( - start: string, - end?: T - ): HelperCond<T, string, { start: Date, end: Date }, undefined, { start: Date, end: undefined }> { - return end !== undefined ? // Ok - { - start: mapDateForAPI(start), - end: mapDateForAPI(end), - } : - { - start: mapDateForAPI(start), - end: undefined - }; - } - - // File: Rocket.Chat/packages/agenda/src/Agenda.ts - type RepeatOptions = object; - type Job = object; - type IJob = { data: object }; - class NewAgenda { - public async _createIntervalJob(interval: string | number, name: string, data: IJob['data'], options: RepeatOptions): Promise<Job> { return undefined as any; } - private _createIntervalJobs( - interval: string | number, - names: string[], - data: IJob['data'], - options: RepeatOptions, - ): Promise<Job[]> | undefined { return undefined as any; } - - public async newEvery<T extends string | string[]>( - interval: string | number, - name: T, - data: IJob['data'], - options: RepeatOptions): Promise<HelperCond<T, string, Job, string[], Job[] | undefined>> { - if (typeof name === 'string') { - return this._createIntervalJob(interval, name, data, options); // Ok - } - - if (Array.isArray(name)) { - return this._createIntervalJobs(interval, name, data, options); // Ok - // Possible bug in original: createIntervalJobs can return undefined, but the original overload did not acount for that. - } - - throw new Error('Unexpected error: Invalid job name(s)'); - } - } - - // File: angular/packages/common/src/pipes/case_conversion_pipes.ts - - function transform1<T extends string | null | undefined>(value: T): HelperCond<T, string, string, null | undefined, null> { - if (value == null) return null; // Ok - if (typeof value !== 'string') { - throw new Error(); - } - return value.toLowerCase(); // Ok - } \ No newline at end of file diff --git a/tests/baselines/reference/dependentReturnType3.symbols b/tests/baselines/reference/dependentReturnType3.symbols deleted file mode 100644 index 3d39bf1559fba..0000000000000 --- a/tests/baselines/reference/dependentReturnType3.symbols +++ /dev/null @@ -1,679 +0,0 @@ -//// [tests/cases/compiler/dependentReturnType3.ts] //// - -=== dependentReturnType3.ts === -// Adapted from ts-error-deltas repos - -type HelperCond<T, A, R1, B, R2> = ->HelperCond : Symbol(HelperCond, Decl(dependentReturnType3.ts, 0, 0)) ->T : Symbol(T, Decl(dependentReturnType3.ts, 2, 16)) ->A : Symbol(A, Decl(dependentReturnType3.ts, 2, 18)) ->R1 : Symbol(R1, Decl(dependentReturnType3.ts, 2, 21)) ->B : Symbol(B, Decl(dependentReturnType3.ts, 2, 25)) ->R2 : Symbol(R2, Decl(dependentReturnType3.ts, 2, 28)) - - T extends A ->T : Symbol(T, Decl(dependentReturnType3.ts, 2, 16)) ->A : Symbol(A, Decl(dependentReturnType3.ts, 2, 18)) - - ? R1 ->R1 : Symbol(R1, Decl(dependentReturnType3.ts, 2, 21)) - - : T extends B ->T : Symbol(T, Decl(dependentReturnType3.ts, 2, 16)) ->B : Symbol(B, Decl(dependentReturnType3.ts, 2, 25)) - - ? R2 ->R2 : Symbol(R2, Decl(dependentReturnType3.ts, 2, 28)) - - : never; - - -// File: Rocket.Chat/apps/meteor/app/katex/client/index.ts -interface IMessage { ->IMessage : Symbol(IMessage, Decl(dependentReturnType3.ts, 7, 20)) - - html?: string; ->html : Symbol(IMessage.html, Decl(dependentReturnType3.ts, 11, 20)) - - tokens?: {}[]; ->tokens : Symbol(IMessage.tokens, Decl(dependentReturnType3.ts, 12, 18)) -} - -class NewKatex { ->NewKatex : Symbol(NewKatex, Decl(dependentReturnType3.ts, 14, 1)) - - render(s: string): string { ->render : Symbol(NewKatex.render, Decl(dependentReturnType3.ts, 16, 16)) ->s : Symbol(s, Decl(dependentReturnType3.ts, 17, 11)) - - return ""; - } - - renderMessage<T extends string | IMessage>(message: T): ->renderMessage : Symbol(NewKatex.renderMessage, Decl(dependentReturnType3.ts, 19, 5)) ->T : Symbol(T, Decl(dependentReturnType3.ts, 21, 18)) ->IMessage : Symbol(IMessage, Decl(dependentReturnType3.ts, 7, 20)) ->message : Symbol(message, Decl(dependentReturnType3.ts, 21, 47)) ->T : Symbol(T, Decl(dependentReturnType3.ts, 21, 18)) - - T extends string ->T : Symbol(T, Decl(dependentReturnType3.ts, 21, 18)) - - ? string - : T extends IMessage ->T : Symbol(T, Decl(dependentReturnType3.ts, 21, 18)) ->IMessage : Symbol(IMessage, Decl(dependentReturnType3.ts, 7, 20)) - - ? IMessage ->IMessage : Symbol(IMessage, Decl(dependentReturnType3.ts, 7, 20)) - - : never { - if (typeof message === 'string') { ->message : Symbol(message, Decl(dependentReturnType3.ts, 21, 47)) - - return this.render(message); // Ok ->this.render : Symbol(NewKatex.render, Decl(dependentReturnType3.ts, 16, 16)) ->this : Symbol(NewKatex, Decl(dependentReturnType3.ts, 14, 1)) ->render : Symbol(NewKatex.render, Decl(dependentReturnType3.ts, 16, 16)) ->message : Symbol(message, Decl(dependentReturnType3.ts, 21, 47)) - } - - if (!message.html?.trim()) { ->message.html?.trim : Symbol(String.trim, Decl(lib.es5.d.ts, --, --)) ->message.html : Symbol(IMessage.html, Decl(dependentReturnType3.ts, 11, 20)) ->message : Symbol(message, Decl(dependentReturnType3.ts, 21, 47)) ->html : Symbol(IMessage.html, Decl(dependentReturnType3.ts, 11, 20)) ->trim : Symbol(String.trim, Decl(lib.es5.d.ts, --, --)) - - return message; // Ok ->message : Symbol(message, Decl(dependentReturnType3.ts, 21, 47)) - } - - if (!message.tokens) { ->message.tokens : Symbol(IMessage.tokens, Decl(dependentReturnType3.ts, 12, 18)) ->message : Symbol(message, Decl(dependentReturnType3.ts, 21, 47)) ->tokens : Symbol(IMessage.tokens, Decl(dependentReturnType3.ts, 12, 18)) - - message.tokens = []; ->message.tokens : Symbol(IMessage.tokens, Decl(dependentReturnType3.ts, 12, 18)) ->message : Symbol(message, Decl(dependentReturnType3.ts, 21, 47)) ->tokens : Symbol(IMessage.tokens, Decl(dependentReturnType3.ts, 12, 18)) - } - - message.html = this.render(message.html); ->message.html : Symbol(IMessage.html, Decl(dependentReturnType3.ts, 11, 20)) ->message : Symbol(message, Decl(dependentReturnType3.ts, 21, 47)) ->html : Symbol(IMessage.html, Decl(dependentReturnType3.ts, 11, 20)) ->this.render : Symbol(NewKatex.render, Decl(dependentReturnType3.ts, 16, 16)) ->this : Symbol(NewKatex, Decl(dependentReturnType3.ts, 14, 1)) ->render : Symbol(NewKatex.render, Decl(dependentReturnType3.ts, 16, 16)) ->message.html : Symbol(IMessage.html, Decl(dependentReturnType3.ts, 11, 20)) ->message : Symbol(message, Decl(dependentReturnType3.ts, 21, 47)) ->html : Symbol(IMessage.html, Decl(dependentReturnType3.ts, 11, 20)) - - return message; // Ok ->message : Symbol(message, Decl(dependentReturnType3.ts, 21, 47)) - } -} - -export function createKatexMessageRendering<T extends true | false>( ->createKatexMessageRendering : Symbol(createKatexMessageRendering, Decl(dependentReturnType3.ts, 42, 1)) ->T : Symbol(T, Decl(dependentReturnType3.ts, 44, 44)) - - options: { ->options : Symbol(options, Decl(dependentReturnType3.ts, 44, 68)) - - dollarSyntax: boolean; ->dollarSyntax : Symbol(dollarSyntax, Decl(dependentReturnType3.ts, 45, 14)) - - parenthesisSyntax: boolean; ->parenthesisSyntax : Symbol(parenthesisSyntax, Decl(dependentReturnType3.ts, 46, 30)) - - }, - _isMessage: T, ->_isMessage : Symbol(_isMessage, Decl(dependentReturnType3.ts, 48, 6)) ->T : Symbol(T, Decl(dependentReturnType3.ts, 44, 44)) - -): T extends true ->T : Symbol(T, Decl(dependentReturnType3.ts, 44, 44)) - - ? (message: IMessage) => IMessage ->message : Symbol(message, Decl(dependentReturnType3.ts, 51, 7)) ->IMessage : Symbol(IMessage, Decl(dependentReturnType3.ts, 7, 20)) ->IMessage : Symbol(IMessage, Decl(dependentReturnType3.ts, 7, 20)) - - : T extends false ->T : Symbol(T, Decl(dependentReturnType3.ts, 44, 44)) - - ? (message: string) => string ->message : Symbol(message, Decl(dependentReturnType3.ts, 53, 9)) - - : never { - const instance = new NewKatex(); ->instance : Symbol(instance, Decl(dependentReturnType3.ts, 55, 9)) ->NewKatex : Symbol(NewKatex, Decl(dependentReturnType3.ts, 14, 1)) - - if (_isMessage) { ->_isMessage : Symbol(_isMessage, Decl(dependentReturnType3.ts, 48, 6)) - - return (message: IMessage): IMessage => instance.renderMessage(message); // Ok ->message : Symbol(message, Decl(dependentReturnType3.ts, 57, 16)) ->IMessage : Symbol(IMessage, Decl(dependentReturnType3.ts, 7, 20)) ->IMessage : Symbol(IMessage, Decl(dependentReturnType3.ts, 7, 20)) ->instance.renderMessage : Symbol(NewKatex.renderMessage, Decl(dependentReturnType3.ts, 19, 5)) ->instance : Symbol(instance, Decl(dependentReturnType3.ts, 55, 9)) ->renderMessage : Symbol(NewKatex.renderMessage, Decl(dependentReturnType3.ts, 19, 5)) ->message : Symbol(message, Decl(dependentReturnType3.ts, 57, 16)) - } - return (message: string): string => instance.renderMessage(message); // Ok ->message : Symbol(message, Decl(dependentReturnType3.ts, 59, 12)) ->instance.renderMessage : Symbol(NewKatex.renderMessage, Decl(dependentReturnType3.ts, 19, 5)) ->instance : Symbol(instance, Decl(dependentReturnType3.ts, 55, 9)) ->renderMessage : Symbol(NewKatex.renderMessage, Decl(dependentReturnType3.ts, 19, 5)) ->message : Symbol(message, Decl(dependentReturnType3.ts, 59, 12)) -} - -// File: Rocket.Chat/apps/meteor/app/settings/lib/settings.ts -type SettingComposedValue<T extends SettingValue = SettingValue> = { key: string; value: T }; ->SettingComposedValue : Symbol(SettingComposedValue, Decl(dependentReturnType3.ts, 60, 1)) ->T : Symbol(T, Decl(dependentReturnType3.ts, 63, 26)) ->SettingValue : Symbol(SettingValue, Decl(dependentReturnType3.ts, 64, 89)) ->SettingValue : Symbol(SettingValue, Decl(dependentReturnType3.ts, 64, 89)) ->key : Symbol(key, Decl(dependentReturnType3.ts, 63, 68)) ->value : Symbol(value, Decl(dependentReturnType3.ts, 63, 81)) ->T : Symbol(T, Decl(dependentReturnType3.ts, 63, 26)) - -type SettingCallback = (key: string, value: SettingValue, initialLoad?: boolean) => void; ->SettingCallback : Symbol(SettingCallback, Decl(dependentReturnType3.ts, 63, 93)) ->key : Symbol(key, Decl(dependentReturnType3.ts, 64, 24)) ->value : Symbol(value, Decl(dependentReturnType3.ts, 64, 36)) ->SettingValue : Symbol(SettingValue, Decl(dependentReturnType3.ts, 64, 89)) ->initialLoad : Symbol(initialLoad, Decl(dependentReturnType3.ts, 64, 57)) - -type SettingValue = object; ->SettingValue : Symbol(SettingValue, Decl(dependentReturnType3.ts, 64, 89)) - -declare const Meteor: { settings: { [s: string]: any } }; ->Meteor : Symbol(Meteor, Decl(dependentReturnType3.ts, 67, 13)) ->settings : Symbol(settings, Decl(dependentReturnType3.ts, 67, 23)) ->s : Symbol(s, Decl(dependentReturnType3.ts, 67, 37)) - -declare const _: { isRegExp(x: unknown): x is RegExp; }; ->_ : Symbol(_, Decl(dependentReturnType3.ts, 68, 13)) ->isRegExp : Symbol(isRegExp, Decl(dependentReturnType3.ts, 68, 18)) ->x : Symbol(x, Decl(dependentReturnType3.ts, 68, 28)) ->x : Symbol(x, Decl(dependentReturnType3.ts, 68, 28)) ->RegExp : Symbol(RegExp, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) - -declare function takesRegExp(x: RegExp): void; ->takesRegExp : Symbol(takesRegExp, Decl(dependentReturnType3.ts, 68, 56)) ->x : Symbol(x, Decl(dependentReturnType3.ts, 69, 29)) ->RegExp : Symbol(RegExp, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) - -declare function takesString(x: string): void; ->takesString : Symbol(takesString, Decl(dependentReturnType3.ts, 69, 46)) ->x : Symbol(x, Decl(dependentReturnType3.ts, 70, 29)) - -class NewSettingsBase { ->NewSettingsBase : Symbol(NewSettingsBase, Decl(dependentReturnType3.ts, 70, 46)) - - public newGet<C extends SettingCallback | undefined, I extends string | RegExp, T extends SettingValue = SettingValue>( ->newGet : Symbol(NewSettingsBase.newGet, Decl(dependentReturnType3.ts, 72, 23)) ->C : Symbol(C, Decl(dependentReturnType3.ts, 73, 18)) ->SettingCallback : Symbol(SettingCallback, Decl(dependentReturnType3.ts, 63, 93)) ->I : Symbol(I, Decl(dependentReturnType3.ts, 73, 56)) ->RegExp : Symbol(RegExp, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) ->T : Symbol(T, Decl(dependentReturnType3.ts, 73, 83)) ->SettingValue : Symbol(SettingValue, Decl(dependentReturnType3.ts, 64, 89)) ->SettingValue : Symbol(SettingValue, Decl(dependentReturnType3.ts, 64, 89)) - - _id: I, ->_id : Symbol(_id, Decl(dependentReturnType3.ts, 73, 123)) ->I : Symbol(I, Decl(dependentReturnType3.ts, 73, 56)) - - callback?: C, ->callback : Symbol(callback, Decl(dependentReturnType3.ts, 74, 15)) ->C : Symbol(C, Decl(dependentReturnType3.ts, 73, 18)) - - ): HelperCond<C, ->HelperCond : Symbol(HelperCond, Decl(dependentReturnType3.ts, 0, 0)) ->C : Symbol(C, Decl(dependentReturnType3.ts, 73, 18)) - - SettingCallback, void, ->SettingCallback : Symbol(SettingCallback, Decl(dependentReturnType3.ts, 63, 93)) - - undefined, HelperCond<I, ->HelperCond : Symbol(HelperCond, Decl(dependentReturnType3.ts, 0, 0)) ->I : Symbol(I, Decl(dependentReturnType3.ts, 73, 56)) - - string, T | undefined, ->T : Symbol(T, Decl(dependentReturnType3.ts, 73, 83)) - - RegExp, SettingComposedValue<T>[]>> { ->RegExp : Symbol(RegExp, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) ->SettingComposedValue : Symbol(SettingComposedValue, Decl(dependentReturnType3.ts, 60, 1)) ->T : Symbol(T, Decl(dependentReturnType3.ts, 73, 83)) - - if (callback !== undefined) { ->callback : Symbol(callback, Decl(dependentReturnType3.ts, 74, 15)) ->undefined : Symbol(undefined) - - if (!Meteor.settings) { ->Meteor.settings : Symbol(settings, Decl(dependentReturnType3.ts, 67, 23)) ->Meteor : Symbol(Meteor, Decl(dependentReturnType3.ts, 67, 13)) ->settings : Symbol(settings, Decl(dependentReturnType3.ts, 67, 23)) - - return; // Ok - } - if (_id === '*') { ->_id : Symbol(_id, Decl(dependentReturnType3.ts, 73, 123)) - - return Object.keys(Meteor.settings).forEach((key) => { // Ok ->Object.keys(Meteor.settings).forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --)) ->Object.keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) ->Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) ->keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) ->Meteor.settings : Symbol(settings, Decl(dependentReturnType3.ts, 67, 23)) ->Meteor : Symbol(Meteor, Decl(dependentReturnType3.ts, 67, 13)) ->settings : Symbol(settings, Decl(dependentReturnType3.ts, 67, 23)) ->forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --)) ->key : Symbol(key, Decl(dependentReturnType3.ts, 86, 61)) - - const value = Meteor.settings[key]; ->value : Symbol(value, Decl(dependentReturnType3.ts, 87, 25)) ->Meteor.settings : Symbol(settings, Decl(dependentReturnType3.ts, 67, 23)) ->Meteor : Symbol(Meteor, Decl(dependentReturnType3.ts, 67, 13)) ->settings : Symbol(settings, Decl(dependentReturnType3.ts, 67, 23)) ->key : Symbol(key, Decl(dependentReturnType3.ts, 86, 61)) - - callback(key, value); ->callback : Symbol(callback, Decl(dependentReturnType3.ts, 74, 15)) ->key : Symbol(key, Decl(dependentReturnType3.ts, 86, 61)) ->value : Symbol(value, Decl(dependentReturnType3.ts, 87, 25)) - - }); - } - if (_.isRegExp(_id) && Meteor.settings) { ->_.isRegExp : Symbol(isRegExp, Decl(dependentReturnType3.ts, 68, 18)) ->_ : Symbol(_, Decl(dependentReturnType3.ts, 68, 13)) ->isRegExp : Symbol(isRegExp, Decl(dependentReturnType3.ts, 68, 18)) ->_id : Symbol(_id, Decl(dependentReturnType3.ts, 73, 123)) ->Meteor.settings : Symbol(settings, Decl(dependentReturnType3.ts, 67, 23)) ->Meteor : Symbol(Meteor, Decl(dependentReturnType3.ts, 67, 13)) ->settings : Symbol(settings, Decl(dependentReturnType3.ts, 67, 23)) - - return Object.keys(Meteor.settings).forEach((key) => { // Ok ->Object.keys(Meteor.settings).forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --)) ->Object.keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) ->Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) ->keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) ->Meteor.settings : Symbol(settings, Decl(dependentReturnType3.ts, 67, 23)) ->Meteor : Symbol(Meteor, Decl(dependentReturnType3.ts, 67, 13)) ->settings : Symbol(settings, Decl(dependentReturnType3.ts, 67, 23)) ->forEach : Symbol(Array.forEach, Decl(lib.es5.d.ts, --, --)) ->key : Symbol(key, Decl(dependentReturnType3.ts, 92, 61)) - - if (!_id.test(key)) { ->_id.test : Symbol(RegExp.test, Decl(lib.es5.d.ts, --, --)) ->_id : Symbol(_id, Decl(dependentReturnType3.ts, 73, 123)) ->test : Symbol(RegExp.test, Decl(lib.es5.d.ts, --, --)) ->key : Symbol(key, Decl(dependentReturnType3.ts, 92, 61)) - - return; - } - const value = Meteor.settings[key]; ->value : Symbol(value, Decl(dependentReturnType3.ts, 96, 25)) ->Meteor.settings : Symbol(settings, Decl(dependentReturnType3.ts, 67, 23)) ->Meteor : Symbol(Meteor, Decl(dependentReturnType3.ts, 67, 13)) ->settings : Symbol(settings, Decl(dependentReturnType3.ts, 67, 23)) ->key : Symbol(key, Decl(dependentReturnType3.ts, 92, 61)) - - callback(key, value); ->callback : Symbol(callback, Decl(dependentReturnType3.ts, 74, 15)) ->key : Symbol(key, Decl(dependentReturnType3.ts, 92, 61)) ->value : Symbol(value, Decl(dependentReturnType3.ts, 96, 25)) - - }); - } - - if (typeof _id === 'string') { ->_id : Symbol(_id, Decl(dependentReturnType3.ts, 73, 123)) - - const value = Meteor.settings[_id]; ->value : Symbol(value, Decl(dependentReturnType3.ts, 102, 21)) ->Meteor.settings : Symbol(settings, Decl(dependentReturnType3.ts, 67, 23)) ->Meteor : Symbol(Meteor, Decl(dependentReturnType3.ts, 67, 13)) ->settings : Symbol(settings, Decl(dependentReturnType3.ts, 67, 23)) ->_id : Symbol(_id, Decl(dependentReturnType3.ts, 73, 123)) - - if (value != null) { ->value : Symbol(value, Decl(dependentReturnType3.ts, 102, 21)) - - callback(_id, Meteor.settings[_id]); ->callback : Symbol(callback, Decl(dependentReturnType3.ts, 74, 15)) ->_id : Symbol(_id, Decl(dependentReturnType3.ts, 73, 123)) ->Meteor.settings : Symbol(settings, Decl(dependentReturnType3.ts, 67, 23)) ->Meteor : Symbol(Meteor, Decl(dependentReturnType3.ts, 67, 13)) ->settings : Symbol(settings, Decl(dependentReturnType3.ts, 67, 23)) ->_id : Symbol(_id, Decl(dependentReturnType3.ts, 73, 123)) - } - return; // Ok - } - - return; // Ok, needed for exhaustiveness check - } - - if (!Meteor.settings) { // Wrong: we don't know that _id is string here, cannot return undefined ->Meteor.settings : Symbol(settings, Decl(dependentReturnType3.ts, 67, 23)) ->Meteor : Symbol(Meteor, Decl(dependentReturnType3.ts, 67, 13)) ->settings : Symbol(settings, Decl(dependentReturnType3.ts, 67, 23)) - - return undefined; // Error ->undefined : Symbol(undefined) - } - - if (_.isRegExp(_id)) { ->_.isRegExp : Symbol(isRegExp, Decl(dependentReturnType3.ts, 68, 18)) ->_ : Symbol(_, Decl(dependentReturnType3.ts, 68, 13)) ->isRegExp : Symbol(isRegExp, Decl(dependentReturnType3.ts, 68, 18)) ->_id : Symbol(_id, Decl(dependentReturnType3.ts, 73, 123)) - - return Object.keys(Meteor.settings).reduce((items: SettingComposedValue<T>[], key) => { ->Object.keys(Meteor.settings).reduce : Symbol(Array.reduce, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) ->Object.keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) ->Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) ->keys : Symbol(ObjectConstructor.keys, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) ->Meteor.settings : Symbol(settings, Decl(dependentReturnType3.ts, 67, 23)) ->Meteor : Symbol(Meteor, Decl(dependentReturnType3.ts, 67, 13)) ->settings : Symbol(settings, Decl(dependentReturnType3.ts, 67, 23)) ->reduce : Symbol(Array.reduce, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) ->items : Symbol(items, Decl(dependentReturnType3.ts, 117, 56)) ->SettingComposedValue : Symbol(SettingComposedValue, Decl(dependentReturnType3.ts, 60, 1)) ->T : Symbol(T, Decl(dependentReturnType3.ts, 73, 83)) ->key : Symbol(key, Decl(dependentReturnType3.ts, 117, 89)) - - const value = Meteor.settings[key]; ->value : Symbol(value, Decl(dependentReturnType3.ts, 118, 9)) ->Meteor.settings : Symbol(settings, Decl(dependentReturnType3.ts, 67, 23)) ->Meteor : Symbol(Meteor, Decl(dependentReturnType3.ts, 67, 13)) ->settings : Symbol(settings, Decl(dependentReturnType3.ts, 67, 23)) ->key : Symbol(key, Decl(dependentReturnType3.ts, 117, 89)) - - if (_id.test(key)) { ->_id.test : Symbol(RegExp.test, Decl(lib.es5.d.ts, --, --)) ->_id : Symbol(_id, Decl(dependentReturnType3.ts, 73, 123)) ->test : Symbol(RegExp.test, Decl(lib.es5.d.ts, --, --)) ->key : Symbol(key, Decl(dependentReturnType3.ts, 117, 89)) - - items.push({ ->items.push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --)) ->items : Symbol(items, Decl(dependentReturnType3.ts, 117, 56)) ->push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --)) - - key, ->key : Symbol(key, Decl(dependentReturnType3.ts, 120, 17)) - - value, ->value : Symbol(value, Decl(dependentReturnType3.ts, 121, 10)) - - }); - } - return items; ->items : Symbol(items, Decl(dependentReturnType3.ts, 117, 56)) - - }, []); // Ok - } - - return Meteor.settings?.[_id]; // Error ->Meteor.settings : Symbol(settings, Decl(dependentReturnType3.ts, 67, 23)) ->Meteor : Symbol(Meteor, Decl(dependentReturnType3.ts, 67, 13)) ->settings : Symbol(settings, Decl(dependentReturnType3.ts, 67, 23)) ->_id : Symbol(_id, Decl(dependentReturnType3.ts, 73, 123)) - - // The indexing currently doesn't work because it doesn't use the narrowed type of `_id`. - } -} - -// File: Rocket.Chat/apps/meteor/app/ui-utils/client/lib/messageBox.ts -type MessageBoxAction = object; ->MessageBoxAction : Symbol(MessageBoxAction, Decl(dependentReturnType3.ts, 132, 1)) - -function getWithBug<T extends string | undefined>(group: T): ->getWithBug : Symbol(getWithBug, Decl(dependentReturnType3.ts, 135, 31)) ->T : Symbol(T, Decl(dependentReturnType3.ts, 137, 20)) ->group : Symbol(group, Decl(dependentReturnType3.ts, 137, 50)) ->T : Symbol(T, Decl(dependentReturnType3.ts, 137, 20)) - -HelperCond<T, string, MessageBoxAction[], undefined, Record<string, MessageBoxAction[]>> { ->HelperCond : Symbol(HelperCond, Decl(dependentReturnType3.ts, 0, 0)) ->T : Symbol(T, Decl(dependentReturnType3.ts, 137, 20)) ->MessageBoxAction : Symbol(MessageBoxAction, Decl(dependentReturnType3.ts, 132, 1)) ->Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) ->MessageBoxAction : Symbol(MessageBoxAction, Decl(dependentReturnType3.ts, 132, 1)) - - if (!group) { ->group : Symbol(group, Decl(dependentReturnType3.ts, 137, 50)) - - return {} as Record<string, MessageBoxAction[]>; // Error, could fall into this branch when group is empty string ->Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) ->MessageBoxAction : Symbol(MessageBoxAction, Decl(dependentReturnType3.ts, 132, 1)) - } - - return [] as MessageBoxAction[]; // Ok ->MessageBoxAction : Symbol(MessageBoxAction, Decl(dependentReturnType3.ts, 132, 1)) -} - -function getWithoutBug<T extends string | undefined>(group: T): ->getWithoutBug : Symbol(getWithoutBug, Decl(dependentReturnType3.ts, 144, 1)) ->T : Symbol(T, Decl(dependentReturnType3.ts, 146, 23)) ->group : Symbol(group, Decl(dependentReturnType3.ts, 146, 53)) ->T : Symbol(T, Decl(dependentReturnType3.ts, 146, 23)) - -HelperCond<T, string, MessageBoxAction[], undefined, Record<string, MessageBoxAction[]>> { ->HelperCond : Symbol(HelperCond, Decl(dependentReturnType3.ts, 0, 0)) ->T : Symbol(T, Decl(dependentReturnType3.ts, 146, 23)) ->MessageBoxAction : Symbol(MessageBoxAction, Decl(dependentReturnType3.ts, 132, 1)) ->Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) ->MessageBoxAction : Symbol(MessageBoxAction, Decl(dependentReturnType3.ts, 132, 1)) - - if (group === undefined) { ->group : Symbol(group, Decl(dependentReturnType3.ts, 146, 53)) ->undefined : Symbol(undefined) - - return {} as Record<string, MessageBoxAction[]>; // Ok ->Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) ->MessageBoxAction : Symbol(MessageBoxAction, Decl(dependentReturnType3.ts, 132, 1)) - } - - return [] as MessageBoxAction[]; // Ok ->MessageBoxAction : Symbol(MessageBoxAction, Decl(dependentReturnType3.ts, 132, 1)) -} - -// File: Rocket.Chat/apps/meteor/ee/server/lib/engagementDashboard/date.ts -declare function mapDateForAPI(x: string): Date; ->mapDateForAPI : Symbol(mapDateForAPI, Decl(dependentReturnType3.ts, 153, 1)) ->x : Symbol(x, Decl(dependentReturnType3.ts, 156, 31)) ->Date : Symbol(Date, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.scripthost.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) - -export function transformDatesForAPI<T extends string | undefined>( ->transformDatesForAPI : Symbol(transformDatesForAPI, Decl(dependentReturnType3.ts, 156, 48)) ->T : Symbol(T, Decl(dependentReturnType3.ts, 157, 37)) - - start: string, ->start : Symbol(start, Decl(dependentReturnType3.ts, 157, 67)) - - end?: T ->end : Symbol(end, Decl(dependentReturnType3.ts, 158, 18)) ->T : Symbol(T, Decl(dependentReturnType3.ts, 157, 37)) - -): HelperCond<T, string, { start: Date, end: Date }, undefined, { start: Date, end: undefined }> { ->HelperCond : Symbol(HelperCond, Decl(dependentReturnType3.ts, 0, 0)) ->T : Symbol(T, Decl(dependentReturnType3.ts, 157, 37)) ->start : Symbol(start, Decl(dependentReturnType3.ts, 160, 26)) ->Date : Symbol(Date, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.scripthost.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) ->end : Symbol(end, Decl(dependentReturnType3.ts, 160, 39)) ->Date : Symbol(Date, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.scripthost.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) ->start : Symbol(start, Decl(dependentReturnType3.ts, 160, 65)) ->Date : Symbol(Date, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.scripthost.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) ->end : Symbol(end, Decl(dependentReturnType3.ts, 160, 78)) - - return end !== undefined ? // Ok ->end : Symbol(end, Decl(dependentReturnType3.ts, 158, 18)) ->undefined : Symbol(undefined) - { - start: mapDateForAPI(start), ->start : Symbol(start, Decl(dependentReturnType3.ts, 162, 9)) ->mapDateForAPI : Symbol(mapDateForAPI, Decl(dependentReturnType3.ts, 153, 1)) ->start : Symbol(start, Decl(dependentReturnType3.ts, 157, 67)) - - end: mapDateForAPI(end), ->end : Symbol(end, Decl(dependentReturnType3.ts, 163, 40)) ->mapDateForAPI : Symbol(mapDateForAPI, Decl(dependentReturnType3.ts, 153, 1)) ->end : Symbol(end, Decl(dependentReturnType3.ts, 158, 18)) - - } : - { - start: mapDateForAPI(start), ->start : Symbol(start, Decl(dependentReturnType3.ts, 166, 9)) ->mapDateForAPI : Symbol(mapDateForAPI, Decl(dependentReturnType3.ts, 153, 1)) ->start : Symbol(start, Decl(dependentReturnType3.ts, 157, 67)) - - end: undefined ->end : Symbol(end, Decl(dependentReturnType3.ts, 167, 40)) ->undefined : Symbol(undefined) - - }; -} - -// File: Rocket.Chat/packages/agenda/src/Agenda.ts -type RepeatOptions = object; ->RepeatOptions : Symbol(RepeatOptions, Decl(dependentReturnType3.ts, 170, 1)) - -type Job = object; ->Job : Symbol(Job, Decl(dependentReturnType3.ts, 173, 28)) - -type IJob = { data: object }; ->IJob : Symbol(IJob, Decl(dependentReturnType3.ts, 174, 18)) ->data : Symbol(data, Decl(dependentReturnType3.ts, 175, 13)) - -class NewAgenda { ->NewAgenda : Symbol(NewAgenda, Decl(dependentReturnType3.ts, 175, 29)) - - public async _createIntervalJob(interval: string | number, name: string, data: IJob['data'], options: RepeatOptions): Promise<Job> { return undefined as any; } ->_createIntervalJob : Symbol(NewAgenda._createIntervalJob, Decl(dependentReturnType3.ts, 176, 17)) ->interval : Symbol(interval, Decl(dependentReturnType3.ts, 177, 36)) ->name : Symbol(name, Decl(dependentReturnType3.ts, 177, 62)) ->data : Symbol(data, Decl(dependentReturnType3.ts, 177, 76)) ->IJob : Symbol(IJob, Decl(dependentReturnType3.ts, 174, 18)) ->options : Symbol(options, Decl(dependentReturnType3.ts, 177, 96)) ->RepeatOptions : Symbol(RepeatOptions, Decl(dependentReturnType3.ts, 170, 1)) ->Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) ->Job : Symbol(Job, Decl(dependentReturnType3.ts, 173, 28)) ->undefined : Symbol(undefined) - - private _createIntervalJobs( ->_createIntervalJobs : Symbol(NewAgenda._createIntervalJobs, Decl(dependentReturnType3.ts, 177, 163)) - - interval: string | number, ->interval : Symbol(interval, Decl(dependentReturnType3.ts, 178, 32)) - - names: string[], ->names : Symbol(names, Decl(dependentReturnType3.ts, 179, 34)) - - data: IJob['data'], ->data : Symbol(data, Decl(dependentReturnType3.ts, 180, 24)) ->IJob : Symbol(IJob, Decl(dependentReturnType3.ts, 174, 18)) - - options: RepeatOptions, ->options : Symbol(options, Decl(dependentReturnType3.ts, 181, 27)) ->RepeatOptions : Symbol(RepeatOptions, Decl(dependentReturnType3.ts, 170, 1)) - - ): Promise<Job[]> | undefined { return undefined as any; } ->Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) ->Job : Symbol(Job, Decl(dependentReturnType3.ts, 173, 28)) ->undefined : Symbol(undefined) - - public async newEvery<T extends string | string[]>( ->newEvery : Symbol(NewAgenda.newEvery, Decl(dependentReturnType3.ts, 183, 62)) ->T : Symbol(T, Decl(dependentReturnType3.ts, 185, 26)) - - interval: string | number, ->interval : Symbol(interval, Decl(dependentReturnType3.ts, 185, 55)) - - name: T, ->name : Symbol(name, Decl(dependentReturnType3.ts, 186, 34)) ->T : Symbol(T, Decl(dependentReturnType3.ts, 185, 26)) - - data: IJob['data'], ->data : Symbol(data, Decl(dependentReturnType3.ts, 187, 16)) ->IJob : Symbol(IJob, Decl(dependentReturnType3.ts, 174, 18)) - - options: RepeatOptions): Promise<HelperCond<T, string, Job, string[], Job[] | undefined>> { ->options : Symbol(options, Decl(dependentReturnType3.ts, 188, 27)) ->RepeatOptions : Symbol(RepeatOptions, Decl(dependentReturnType3.ts, 170, 1)) ->Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) ->HelperCond : Symbol(HelperCond, Decl(dependentReturnType3.ts, 0, 0)) ->T : Symbol(T, Decl(dependentReturnType3.ts, 185, 26)) ->Job : Symbol(Job, Decl(dependentReturnType3.ts, 173, 28)) ->Job : Symbol(Job, Decl(dependentReturnType3.ts, 173, 28)) - - if (typeof name === 'string') { ->name : Symbol(name, Decl(dependentReturnType3.ts, 186, 34)) - - return this._createIntervalJob(interval, name, data, options); // Ok ->this._createIntervalJob : Symbol(NewAgenda._createIntervalJob, Decl(dependentReturnType3.ts, 176, 17)) ->this : Symbol(NewAgenda, Decl(dependentReturnType3.ts, 175, 29)) ->_createIntervalJob : Symbol(NewAgenda._createIntervalJob, Decl(dependentReturnType3.ts, 176, 17)) ->interval : Symbol(interval, Decl(dependentReturnType3.ts, 185, 55)) ->name : Symbol(name, Decl(dependentReturnType3.ts, 186, 34)) ->data : Symbol(data, Decl(dependentReturnType3.ts, 187, 16)) ->options : Symbol(options, Decl(dependentReturnType3.ts, 188, 27)) - } - - if (Array.isArray(name)) { ->Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) ->Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) ->isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) ->name : Symbol(name, Decl(dependentReturnType3.ts, 186, 34)) - - return this._createIntervalJobs(interval, name, data, options); // Ok ->this._createIntervalJobs : Symbol(NewAgenda._createIntervalJobs, Decl(dependentReturnType3.ts, 177, 163)) ->this : Symbol(NewAgenda, Decl(dependentReturnType3.ts, 175, 29)) ->_createIntervalJobs : Symbol(NewAgenda._createIntervalJobs, Decl(dependentReturnType3.ts, 177, 163)) ->interval : Symbol(interval, Decl(dependentReturnType3.ts, 185, 55)) ->name : Symbol(name, Decl(dependentReturnType3.ts, 186, 34)) ->data : Symbol(data, Decl(dependentReturnType3.ts, 187, 16)) ->options : Symbol(options, Decl(dependentReturnType3.ts, 188, 27)) - - // Possible bug in original: createIntervalJobs can return undefined, but the original overload did not acount for that. - } - - throw new Error('Unexpected error: Invalid job name(s)'); ->Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) - } -} - -// File: angular/packages/common/src/pipes/case_conversion_pipes.ts - -function transform1<T extends string | null | undefined>(value: T): HelperCond<T, string, string, null | undefined, null> { ->transform1 : Symbol(transform1, Decl(dependentReturnType3.ts, 201, 1)) ->T : Symbol(T, Decl(dependentReturnType3.ts, 205, 20)) ->value : Symbol(value, Decl(dependentReturnType3.ts, 205, 57)) ->T : Symbol(T, Decl(dependentReturnType3.ts, 205, 20)) ->HelperCond : Symbol(HelperCond, Decl(dependentReturnType3.ts, 0, 0)) ->T : Symbol(T, Decl(dependentReturnType3.ts, 205, 20)) - - if (value == null) return null; // Ok ->value : Symbol(value, Decl(dependentReturnType3.ts, 205, 57)) - - if (typeof value !== 'string') { ->value : Symbol(value, Decl(dependentReturnType3.ts, 205, 57)) - - throw new Error(); ->Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) - } - return value.toLowerCase(); // Ok ->value.toLowerCase : Symbol(String.toLowerCase, Decl(lib.es5.d.ts, --, --)) ->value : Symbol(value, Decl(dependentReturnType3.ts, 205, 57)) ->toLowerCase : Symbol(String.toLowerCase, Decl(lib.es5.d.ts, --, --)) -} diff --git a/tests/baselines/reference/dependentReturnType3.types b/tests/baselines/reference/dependentReturnType3.types deleted file mode 100644 index ac94d85e9b9e3..0000000000000 --- a/tests/baselines/reference/dependentReturnType3.types +++ /dev/null @@ -1,1000 +0,0 @@ -//// [tests/cases/compiler/dependentReturnType3.ts] //// - -=== dependentReturnType3.ts === -// Adapted from ts-error-deltas repos - -type HelperCond<T, A, R1, B, R2> = ->HelperCond : HelperCond<T, A, R1, B, R2> -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - T extends A - ? R1 - : T extends B - ? R2 - : never; - - -// File: Rocket.Chat/apps/meteor/app/katex/client/index.ts -interface IMessage { - html?: string; ->html : string | undefined -> : ^^^^^^^^^^^^^^^^^^ - - tokens?: {}[]; ->tokens : {}[] | undefined -> : ^^^^^^^^^^^^^^^^ -} - -class NewKatex { ->NewKatex : NewKatex -> : ^^^^^^^^ - - render(s: string): string { ->render : (s: string) => string -> : ^ ^^ ^^^^^ ->s : string -> : ^^^^^^ - - return ""; ->"" : "" -> : ^^ - } - - renderMessage<T extends string | IMessage>(message: T): ->renderMessage : <T extends string | IMessage>(message: T) => T extends string ? string : T extends IMessage ? IMessage : never -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->message : T -> : ^ - - T extends string - ? string - : T extends IMessage - ? IMessage - : never { - if (typeof message === 'string') { ->typeof message === 'string' : boolean -> : ^^^^^^^ ->typeof message : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->message : T -> : ^ ->'string' : "string" -> : ^^^^^^^^ - - return this.render(message); // Ok ->this.render(message) : string -> : ^^^^^^ ->this.render : (s: string) => string -> : ^ ^^ ^^^^^ ->this : this -> : ^^^^ ->render : (s: string) => string -> : ^ ^^ ^^^^^ ->message : string -> : ^^^^^^ - } - - if (!message.html?.trim()) { ->!message.html?.trim() : boolean -> : ^^^^^^^ ->message.html?.trim() : string | undefined -> : ^^^^^^^^^^^^^^^^^^ ->message.html?.trim : (() => string) | undefined -> : ^^^^^^^ ^^^^^^^^^^^^^ ->message.html : string | undefined -> : ^^^^^^^^^^^^^^^^^^ ->message : IMessage -> : ^^^^^^^^ ->html : string | undefined -> : ^^^^^^^^^^^^^^^^^^ ->trim : (() => string) | undefined -> : ^^^^^^^ ^^^^^^^^^^^^^ - - return message; // Ok ->message : IMessage -> : ^^^^^^^^ - } - - if (!message.tokens) { ->!message.tokens : boolean -> : ^^^^^^^ ->message.tokens : {}[] | undefined -> : ^^^^^^^^^^^^^^^^ ->message : IMessage -> : ^^^^^^^^ ->tokens : {}[] | undefined -> : ^^^^^^^^^^^^^^^^ - - message.tokens = []; ->message.tokens = [] : never[] -> : ^^^^^^^ ->message.tokens : {}[] | undefined -> : ^^^^^^^^^^^^^^^^ ->message : IMessage -> : ^^^^^^^^ ->tokens : {}[] | undefined -> : ^^^^^^^^^^^^^^^^ ->[] : never[] -> : ^^^^^^^ - } - - message.html = this.render(message.html); ->message.html = this.render(message.html) : string -> : ^^^^^^ ->message.html : string | undefined -> : ^^^^^^^^^^^^^^^^^^ ->message : IMessage -> : ^^^^^^^^ ->html : string | undefined -> : ^^^^^^^^^^^^^^^^^^ ->this.render(message.html) : string -> : ^^^^^^ ->this.render : (s: string) => string -> : ^ ^^ ^^^^^ ->this : this -> : ^^^^ ->render : (s: string) => string -> : ^ ^^ ^^^^^ ->message.html : string -> : ^^^^^^ ->message : IMessage -> : ^^^^^^^^ ->html : string -> : ^^^^^^ - - return message; // Ok ->message : IMessage -> : ^^^^^^^^ - } -} - -export function createKatexMessageRendering<T extends true | false>( ->createKatexMessageRendering : <T extends true | false>(options: { dollarSyntax: boolean; parenthesisSyntax: boolean; }, _isMessage: T) => T extends true ? (message: IMessage) => IMessage : T extends false ? (message: string) => string : never -> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^ ->true : true -> : ^^^^ ->false : false -> : ^^^^^ - - options: { ->options : { dollarSyntax: boolean; parenthesisSyntax: boolean; } -> : ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^ ^^^ - - dollarSyntax: boolean; ->dollarSyntax : boolean -> : ^^^^^^^ - - parenthesisSyntax: boolean; ->parenthesisSyntax : boolean -> : ^^^^^^^ - - }, - _isMessage: T, ->_isMessage : T -> : ^ - -): T extends true ->true : true -> : ^^^^ - - ? (message: IMessage) => IMessage ->message : IMessage -> : ^^^^^^^^ - - : T extends false ->false : false -> : ^^^^^ - - ? (message: string) => string ->message : string -> : ^^^^^^ - - : never { - const instance = new NewKatex(); ->instance : NewKatex -> : ^^^^^^^^ ->new NewKatex() : NewKatex -> : ^^^^^^^^ ->NewKatex : typeof NewKatex -> : ^^^^^^^^^^^^^^^ - - if (_isMessage) { ->_isMessage : T -> : ^ - - return (message: IMessage): IMessage => instance.renderMessage(message); // Ok ->(message: IMessage): IMessage => instance.renderMessage(message) : (message: IMessage) => IMessage -> : ^ ^^ ^^^^^ ->message : IMessage -> : ^^^^^^^^ ->instance.renderMessage(message) : IMessage -> : ^^^^^^^^ ->instance.renderMessage : <T_1 extends string | IMessage>(message: T_1) => T_1 extends string ? string : T_1 extends IMessage ? IMessage : never -> : ^^^^^^^^^^^^^ ^^ ^^ ^^^^^ ->instance : NewKatex -> : ^^^^^^^^ ->renderMessage : <T_1 extends string | IMessage>(message: T_1) => T_1 extends string ? string : T_1 extends IMessage ? IMessage : never -> : ^^^^^^^^^^^^^ ^^ ^^ ^^^^^ ->message : IMessage -> : ^^^^^^^^ - } - return (message: string): string => instance.renderMessage(message); // Ok ->(message: string): string => instance.renderMessage(message) : (message: string) => string -> : ^ ^^ ^^^^^ ->message : string -> : ^^^^^^ ->instance.renderMessage(message) : string -> : ^^^^^^ ->instance.renderMessage : <T_1 extends string | IMessage>(message: T_1) => T_1 extends string ? string : T_1 extends IMessage ? IMessage : never -> : ^^^^^^^^^^^^^ ^^ ^^ ^^^^^ ->instance : NewKatex -> : ^^^^^^^^ ->renderMessage : <T_1 extends string | IMessage>(message: T_1) => T_1 extends string ? string : T_1 extends IMessage ? IMessage : never -> : ^^^^^^^^^^^^^ ^^ ^^ ^^^^^ ->message : string -> : ^^^^^^ -} - -// File: Rocket.Chat/apps/meteor/app/settings/lib/settings.ts -type SettingComposedValue<T extends SettingValue = SettingValue> = { key: string; value: T }; ->SettingComposedValue : SettingComposedValue<T> -> : ^^^^^^^^^^^^^^^^^^^^^^^ ->key : string -> : ^^^^^^ ->value : T -> : ^ - -type SettingCallback = (key: string, value: SettingValue, initialLoad?: boolean) => void; ->SettingCallback : SettingCallback -> : ^^^^^^^^^^^^^^^ ->key : string -> : ^^^^^^ ->value : object -> : ^^^^^^ ->initialLoad : boolean | undefined -> : ^^^^^^^^^^^^^^^^^^^ - -type SettingValue = object; ->SettingValue : object -> : ^^^^^^ - -declare const Meteor: { settings: { [s: string]: any } }; ->Meteor : { settings: { [s: string]: any; }; } -> : ^^^^^^^^^^^^ ^^^ ->settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->s : string -> : ^^^^^^ - -declare const _: { isRegExp(x: unknown): x is RegExp; }; ->_ : { isRegExp(x: unknown): x is RegExp; } -> : ^^^^^^^^^^^ ^^ ^^^ ^^^ ->isRegExp : (x: unknown) => x is RegExp -> : ^ ^^ ^^^^^ ->x : unknown -> : ^^^^^^^ - -declare function takesRegExp(x: RegExp): void; ->takesRegExp : (x: RegExp) => void -> : ^ ^^ ^^^^^ ->x : RegExp -> : ^^^^^^ - -declare function takesString(x: string): void; ->takesString : (x: string) => void -> : ^ ^^ ^^^^^ ->x : string -> : ^^^^^^ - -class NewSettingsBase { ->NewSettingsBase : NewSettingsBase -> : ^^^^^^^^^^^^^^^ - - public newGet<C extends SettingCallback | undefined, I extends string | RegExp, T extends SettingValue = SettingValue>( ->newGet : <C extends SettingCallback | undefined, I extends string | RegExp, T extends SettingValue = object>(_id: I, callback?: C) => HelperCond<C, SettingCallback, void, undefined, HelperCond<I, string, T | undefined, RegExp, SettingComposedValue<T>[]>> -> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^^^^^^^^^^ ^^ ^^ ^^^ ^^^^^ - - _id: I, ->_id : I -> : ^ - - callback?: C, ->callback : C | undefined -> : ^^^^^^^^^^^^^ - - ): HelperCond<C, - SettingCallback, void, - undefined, HelperCond<I, - string, T | undefined, - RegExp, SettingComposedValue<T>[]>> { - if (callback !== undefined) { ->callback !== undefined : boolean -> : ^^^^^^^ ->callback : C | undefined -> : ^^^^^^^^^^^^^ ->undefined : undefined -> : ^^^^^^^^^ - - if (!Meteor.settings) { ->!Meteor.settings : false -> : ^^^^^ ->Meteor.settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->Meteor : { settings: { [s: string]: any; }; } -> : ^^^^^^^^^^^^ ^^^ ->settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ - - return; // Ok - } - if (_id === '*') { ->_id === '*' : boolean -> : ^^^^^^^ ->_id : I -> : ^ ->'*' : "*" -> : ^^^ - - return Object.keys(Meteor.settings).forEach((key) => { // Ok ->Object.keys(Meteor.settings).forEach((key) => { // Ok const value = Meteor.settings[key]; callback(key, value); }) : void -> : ^^^^ ->Object.keys(Meteor.settings).forEach : (callbackfn: (value: string, index: number, array: string[]) => void, thisArg?: any) => void -> : ^ ^^^ ^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^ ^^ ^^^ ^^^^^ ->Object.keys(Meteor.settings) : string[] -> : ^^^^^^^^ ->Object.keys : { (o: object): string[]; (o: {}): string[]; } -> : ^^^ ^^ ^^^ ^^^ ^^ ^^^ ^^^ ->Object : ObjectConstructor -> : ^^^^^^^^^^^^^^^^^ ->keys : { (o: object): string[]; (o: {}): string[]; } -> : ^^^ ^^ ^^^ ^^^ ^^ ^^^ ^^^ ->Meteor.settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->Meteor : { settings: { [s: string]: any; }; } -> : ^^^^^^^^^^^^ ^^^ ->settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->forEach : (callbackfn: (value: string, index: number, array: string[]) => void, thisArg?: any) => void -> : ^ ^^^ ^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^ ^^ ^^^ ^^^^^ ->(key) => { // Ok const value = Meteor.settings[key]; callback(key, value); } : (key: string) => void -> : ^ ^^^^^^^^^^^^^^^^^ ->key : string -> : ^^^^^^ - - const value = Meteor.settings[key]; ->value : any -> : ^^^ ->Meteor.settings[key] : any -> : ^^^ ->Meteor.settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->Meteor : { settings: { [s: string]: any; }; } -> : ^^^^^^^^^^^^ ^^^ ->settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->key : string -> : ^^^^^^ - - callback(key, value); ->callback(key, value) : void -> : ^^^^ ->callback : SettingCallback -> : ^^^^^^^^^^^^^^^ ->key : string -> : ^^^^^^ ->value : any -> : ^^^ - - }); - } - if (_.isRegExp(_id) && Meteor.settings) { ->_.isRegExp(_id) && Meteor.settings : false | { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->_.isRegExp(_id) : boolean -> : ^^^^^^^ ->_.isRegExp : (x: unknown) => x is RegExp -> : ^ ^^ ^^^^^ ->_ : { isRegExp(x: unknown): x is RegExp; } -> : ^^^^^^^^^^^ ^^ ^^^ ^^^ ->isRegExp : (x: unknown) => x is RegExp -> : ^ ^^ ^^^^^ ->_id : string | RegExp -> : ^^^^^^^^^^^^^^^ ->Meteor.settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->Meteor : { settings: { [s: string]: any; }; } -> : ^^^^^^^^^^^^ ^^^ ->settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ - - return Object.keys(Meteor.settings).forEach((key) => { // Ok ->Object.keys(Meteor.settings).forEach((key) => { // Ok if (!_id.test(key)) { return; } const value = Meteor.settings[key]; callback(key, value); }) : void -> : ^^^^ ->Object.keys(Meteor.settings).forEach : (callbackfn: (value: string, index: number, array: string[]) => void, thisArg?: any) => void -> : ^ ^^^ ^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^ ^^ ^^^ ^^^^^ ->Object.keys(Meteor.settings) : string[] -> : ^^^^^^^^ ->Object.keys : { (o: object): string[]; (o: {}): string[]; } -> : ^^^ ^^ ^^^ ^^^ ^^ ^^^ ^^^ ->Object : ObjectConstructor -> : ^^^^^^^^^^^^^^^^^ ->keys : { (o: object): string[]; (o: {}): string[]; } -> : ^^^ ^^ ^^^ ^^^ ^^ ^^^ ^^^ ->Meteor.settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->Meteor : { settings: { [s: string]: any; }; } -> : ^^^^^^^^^^^^ ^^^ ->settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->forEach : (callbackfn: (value: string, index: number, array: string[]) => void, thisArg?: any) => void -> : ^ ^^^ ^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^ ^^ ^^^ ^^^^^ ->(key) => { // Ok if (!_id.test(key)) { return; } const value = Meteor.settings[key]; callback(key, value); } : (key: string) => void -> : ^ ^^^^^^^^^^^^^^^^^ ->key : string -> : ^^^^^^ - - if (!_id.test(key)) { ->!_id.test(key) : boolean -> : ^^^^^^^ ->_id.test(key) : boolean -> : ^^^^^^^ ->_id.test : (string: string) => boolean -> : ^ ^^ ^^^^^ ->_id : RegExp -> : ^^^^^^ ->test : (string: string) => boolean -> : ^ ^^ ^^^^^ ->key : string -> : ^^^^^^ - - return; - } - const value = Meteor.settings[key]; ->value : any -> : ^^^ ->Meteor.settings[key] : any -> : ^^^ ->Meteor.settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->Meteor : { settings: { [s: string]: any; }; } -> : ^^^^^^^^^^^^ ^^^ ->settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->key : string -> : ^^^^^^ - - callback(key, value); ->callback(key, value) : void -> : ^^^^ ->callback : SettingCallback -> : ^^^^^^^^^^^^^^^ ->key : string -> : ^^^^^^ ->value : any -> : ^^^ - - }); - } - - if (typeof _id === 'string') { ->typeof _id === 'string' : boolean -> : ^^^^^^^ ->typeof _id : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->_id : I -> : ^ ->'string' : "string" -> : ^^^^^^^^ - - const value = Meteor.settings[_id]; ->value : any -> : ^^^ ->Meteor.settings[_id] : any -> : ^^^ ->Meteor.settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->Meteor : { settings: { [s: string]: any; }; } -> : ^^^^^^^^^^^^ ^^^ ->settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->_id : I & string -> : ^^^^^^^^^^ - - if (value != null) { ->value != null : boolean -> : ^^^^^^^ ->value : any -> : ^^^ - - callback(_id, Meteor.settings[_id]); ->callback(_id, Meteor.settings[_id]) : void -> : ^^^^ ->callback : SettingCallback -> : ^^^^^^^^^^^^^^^ ->_id : string -> : ^^^^^^ ->Meteor.settings[_id] : any -> : ^^^ ->Meteor.settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->Meteor : { settings: { [s: string]: any; }; } -> : ^^^^^^^^^^^^ ^^^ ->settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->_id : I & string -> : ^^^^^^^^^^ - } - return; // Ok - } - - return; // Ok, needed for exhaustiveness check - } - - if (!Meteor.settings) { // Wrong: we don't know that _id is string here, cannot return undefined ->!Meteor.settings : false -> : ^^^^^ ->Meteor.settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->Meteor : { settings: { [s: string]: any; }; } -> : ^^^^^^^^^^^^ ^^^ ->settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ - - return undefined; // Error ->undefined : undefined -> : ^^^^^^^^^ - } - - if (_.isRegExp(_id)) { ->_.isRegExp(_id) : boolean -> : ^^^^^^^ ->_.isRegExp : (x: unknown) => x is RegExp -> : ^ ^^ ^^^^^ ->_ : { isRegExp(x: unknown): x is RegExp; } -> : ^^^^^^^^^^^ ^^ ^^^ ^^^ ->isRegExp : (x: unknown) => x is RegExp -> : ^ ^^ ^^^^^ ->_id : string | RegExp -> : ^^^^^^^^^^^^^^^ - - return Object.keys(Meteor.settings).reduce((items: SettingComposedValue<T>[], key) => { ->Object.keys(Meteor.settings).reduce((items: SettingComposedValue<T>[], key) => { const value = Meteor.settings[key]; if (_id.test(key)) { items.push({ key, value, }); } return items; }, []) : SettingComposedValue<T>[] -> : ^^^^^^^^^^^^^^^^^^^^^^^^^ ->Object.keys(Meteor.settings).reduce : { (callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string): string; (callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string, initialValue: string): string; <U>(callbackfn: (previousValue: U, currentValue: string, currentIndex: number, array: string[]) => U, initialValue: U): U; } -> : ^^^ ^^^ ^^^^^^^^^^ ^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^^^ ^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^ ^^ ^^^ ^^^^^ ^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ->Object.keys(Meteor.settings) : string[] -> : ^^^^^^^^ ->Object.keys : { (o: object): string[]; (o: {}): string[]; } -> : ^^^ ^^ ^^^ ^^^ ^^ ^^^ ^^^ ->Object : ObjectConstructor -> : ^^^^^^^^^^^^^^^^^ ->keys : { (o: object): string[]; (o: {}): string[]; } -> : ^^^ ^^ ^^^ ^^^ ^^ ^^^ ^^^ ->Meteor.settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->Meteor : { settings: { [s: string]: any; }; } -> : ^^^^^^^^^^^^ ^^^ ->settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->reduce : { (callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string): string; (callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string, initialValue: string): string; <U>(callbackfn: (previousValue: U, currentValue: string, currentIndex: number, array: string[]) => U, initialValue: U): U; } -> : ^^^ ^^^ ^^^^^^^^^^ ^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^^^ ^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^ ^^ ^^^ ^^^^^ ^^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ->(items: SettingComposedValue<T>[], key) => { const value = Meteor.settings[key]; if (_id.test(key)) { items.push({ key, value, }); } return items; } : (items: SettingComposedValue<T>[], key: string) => SettingComposedValue<T>[] -> : ^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->items : SettingComposedValue<T>[] -> : ^^^^^^^^^^^^^^^^^^^^^^^^^ ->key : string -> : ^^^^^^ - - const value = Meteor.settings[key]; ->value : any -> : ^^^ ->Meteor.settings[key] : any -> : ^^^ ->Meteor.settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->Meteor : { settings: { [s: string]: any; }; } -> : ^^^^^^^^^^^^ ^^^ ->settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->key : string -> : ^^^^^^ - - if (_id.test(key)) { ->_id.test(key) : boolean -> : ^^^^^^^ ->_id.test : (string: string) => boolean -> : ^ ^^ ^^^^^ ->_id : RegExp -> : ^^^^^^ ->test : (string: string) => boolean -> : ^ ^^ ^^^^^ ->key : string -> : ^^^^^^ - - items.push({ ->items.push({ key, value, }) : number -> : ^^^^^^ ->items.push : (...items: SettingComposedValue<T>[]) => number -> : ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->items : SettingComposedValue<T>[] -> : ^^^^^^^^^^^^^^^^^^^^^^^^^ ->push : (...items: SettingComposedValue<T>[]) => number -> : ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->{ key, value, } : { key: string; value: any; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - key, ->key : string -> : ^^^^^^ - - value, ->value : any -> : ^^^ - - }); - } - return items; ->items : SettingComposedValue<T>[] -> : ^^^^^^^^^^^^^^^^^^^^^^^^^ - - }, []); // Ok ->[] : never[] -> : ^^^^^^^ - } - - return Meteor.settings?.[_id]; // Error ->Meteor.settings?.[_id] : any -> : ^^^ ->Meteor.settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->Meteor : { settings: { [s: string]: any; }; } -> : ^^^^^^^^^^^^ ^^^ ->settings : { [s: string]: any; } -> : ^^^^^^^^^^^^^^^^^^^^^ ->_id : I -> : ^ - - // The indexing currently doesn't work because it doesn't use the narrowed type of `_id`. - } -} - -// File: Rocket.Chat/apps/meteor/app/ui-utils/client/lib/messageBox.ts -type MessageBoxAction = object; ->MessageBoxAction : object -> : ^^^^^^ - -function getWithBug<T extends string | undefined>(group: T): ->getWithBug : <T extends string | undefined>(group: T) => HelperCond<T, string, MessageBoxAction[], undefined, Record<string, MessageBoxAction[]>> -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->group : T -> : ^ - -HelperCond<T, string, MessageBoxAction[], undefined, Record<string, MessageBoxAction[]>> { - if (!group) { ->!group : boolean -> : ^^^^^^^ ->group : T -> : ^ - - return {} as Record<string, MessageBoxAction[]>; // Error, could fall into this branch when group is empty string ->{} as Record<string, MessageBoxAction[]> : Record<string, object[]> -> : ^^^^^^^^^^^^^^^^^^^^^^^^ ->{} : {} -> : ^^ - } - - return [] as MessageBoxAction[]; // Ok ->[] as MessageBoxAction[] : object[] -> : ^^^^^^^^ ->[] : never[] -> : ^^^^^^^ -} - -function getWithoutBug<T extends string | undefined>(group: T): ->getWithoutBug : <T extends string | undefined>(group: T) => HelperCond<T, string, MessageBoxAction[], undefined, Record<string, MessageBoxAction[]>> -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->group : T -> : ^ - -HelperCond<T, string, MessageBoxAction[], undefined, Record<string, MessageBoxAction[]>> { - if (group === undefined) { ->group === undefined : boolean -> : ^^^^^^^ ->group : T -> : ^ ->undefined : undefined -> : ^^^^^^^^^ - - return {} as Record<string, MessageBoxAction[]>; // Ok ->{} as Record<string, MessageBoxAction[]> : Record<string, object[]> -> : ^^^^^^^^^^^^^^^^^^^^^^^^ ->{} : {} -> : ^^ - } - - return [] as MessageBoxAction[]; // Ok ->[] as MessageBoxAction[] : object[] -> : ^^^^^^^^ ->[] : never[] -> : ^^^^^^^ -} - -// File: Rocket.Chat/apps/meteor/ee/server/lib/engagementDashboard/date.ts -declare function mapDateForAPI(x: string): Date; ->mapDateForAPI : (x: string) => Date -> : ^ ^^ ^^^^^ ->x : string -> : ^^^^^^ - -export function transformDatesForAPI<T extends string | undefined>( ->transformDatesForAPI : <T extends string | undefined>(start: string, end?: T) => HelperCond<T, string, { start: Date; end: Date; }, undefined, { start: Date; end: undefined; }> -> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^^ ^^^^^ - - start: string, ->start : string -> : ^^^^^^ - - end?: T ->end : T | undefined -> : ^^^^^^^^^^^^^ - -): HelperCond<T, string, { start: Date, end: Date }, undefined, { start: Date, end: undefined }> { ->start : Date -> : ^^^^ ->end : Date -> : ^^^^ ->start : Date -> : ^^^^ ->end : undefined -> : ^^^^^^^^^ - - return end !== undefined ? // Ok ->end !== undefined ? // Ok { start: mapDateForAPI(start), end: mapDateForAPI(end), } : { start: mapDateForAPI(start), end: undefined } : { start: Date; end: Date; } | { start: Date; end: undefined; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->end !== undefined : boolean -> : ^^^^^^^ ->end : T | undefined -> : ^^^^^^^^^^^^^ ->undefined : undefined -> : ^^^^^^^^^ - { ->{ start: mapDateForAPI(start), end: mapDateForAPI(end), } : { start: Date; end: Date; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - start: mapDateForAPI(start), ->start : Date -> : ^^^^ ->mapDateForAPI(start) : Date -> : ^^^^ ->mapDateForAPI : (x: string) => Date -> : ^ ^^ ^^^^^ ->start : string -> : ^^^^^^ - - end: mapDateForAPI(end), ->end : Date -> : ^^^^ ->mapDateForAPI(end) : Date -> : ^^^^ ->mapDateForAPI : (x: string) => Date -> : ^ ^^ ^^^^^ ->end : string -> : ^^^^^^ - - } : - { ->{ start: mapDateForAPI(start), end: undefined } : { start: Date; end: undefined; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - start: mapDateForAPI(start), ->start : Date -> : ^^^^ ->mapDateForAPI(start) : Date -> : ^^^^ ->mapDateForAPI : (x: string) => Date -> : ^ ^^ ^^^^^ ->start : string -> : ^^^^^^ - - end: undefined ->end : undefined -> : ^^^^^^^^^ ->undefined : undefined -> : ^^^^^^^^^ - - }; -} - -// File: Rocket.Chat/packages/agenda/src/Agenda.ts -type RepeatOptions = object; ->RepeatOptions : object -> : ^^^^^^ - -type Job = object; ->Job : object -> : ^^^^^^ - -type IJob = { data: object }; ->IJob : IJob -> : ^^^^ ->data : object -> : ^^^^^^ - -class NewAgenda { ->NewAgenda : NewAgenda -> : ^^^^^^^^^ - - public async _createIntervalJob(interval: string | number, name: string, data: IJob['data'], options: RepeatOptions): Promise<Job> { return undefined as any; } ->_createIntervalJob : (interval: string | number, name: string, data: IJob["data"], options: RepeatOptions) => Promise<Job> -> : ^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^ ->interval : string | number -> : ^^^^^^^^^^^^^^^ ->name : string -> : ^^^^^^ ->data : object -> : ^^^^^^ ->options : object -> : ^^^^^^ ->undefined as any : any -> : ^^^ ->undefined : undefined -> : ^^^^^^^^^ - - private _createIntervalJobs( ->_createIntervalJobs : (interval: string | number, names: string[], data: IJob["data"], options: RepeatOptions) => Promise<Job[]> | undefined -> : ^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^ - - interval: string | number, ->interval : string | number -> : ^^^^^^^^^^^^^^^ - - names: string[], ->names : string[] -> : ^^^^^^^^ - - data: IJob['data'], ->data : object -> : ^^^^^^ - - options: RepeatOptions, ->options : object -> : ^^^^^^ - - ): Promise<Job[]> | undefined { return undefined as any; } ->undefined as any : any -> : ^^^ ->undefined : undefined -> : ^^^^^^^^^ - - public async newEvery<T extends string | string[]>( ->newEvery : <T extends string | string[]>(interval: string | number, name: T, data: IJob["data"], options: RepeatOptions) => Promise<HelperCond<T, string, Job, string[], Job[] | undefined>> -> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^ - - interval: string | number, ->interval : string | number -> : ^^^^^^^^^^^^^^^ - - name: T, ->name : T -> : ^ - - data: IJob['data'], ->data : object -> : ^^^^^^ - - options: RepeatOptions): Promise<HelperCond<T, string, Job, string[], Job[] | undefined>> { ->options : object -> : ^^^^^^ - - if (typeof name === 'string') { ->typeof name === 'string' : boolean -> : ^^^^^^^ ->typeof name : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->name : T -> : ^ ->'string' : "string" -> : ^^^^^^^^ - - return this._createIntervalJob(interval, name, data, options); // Ok ->this._createIntervalJob(interval, name, data, options) : Promise<object> -> : ^^^^^^^^^^^^^^^ ->this._createIntervalJob : (interval: string | number, name: string, data: IJob["data"], options: RepeatOptions) => Promise<Job> -> : ^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^ ->this : this -> : ^^^^ ->_createIntervalJob : (interval: string | number, name: string, data: IJob["data"], options: RepeatOptions) => Promise<Job> -> : ^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^ ->interval : string | number -> : ^^^^^^^^^^^^^^^ ->name : string -> : ^^^^^^ ->data : object -> : ^^^^^^ ->options : object -> : ^^^^^^ - } - - if (Array.isArray(name)) { ->Array.isArray(name) : boolean -> : ^^^^^^^ ->Array.isArray : (arg: any) => arg is any[] -> : ^ ^^ ^^^^^ ->Array : ArrayConstructor -> : ^^^^^^^^^^^^^^^^ ->isArray : (arg: any) => arg is any[] -> : ^ ^^ ^^^^^ ->name : string[] -> : ^^^^^^^^ - - return this._createIntervalJobs(interval, name, data, options); // Ok ->this._createIntervalJobs(interval, name, data, options) : Promise<object[]> | undefined -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->this._createIntervalJobs : (interval: string | number, names: string[], data: IJob["data"], options: RepeatOptions) => Promise<Job[]> | undefined -> : ^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^ ->this : this -> : ^^^^ ->_createIntervalJobs : (interval: string | number, names: string[], data: IJob["data"], options: RepeatOptions) => Promise<Job[]> | undefined -> : ^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^ ->interval : string | number -> : ^^^^^^^^^^^^^^^ ->name : string[] -> : ^^^^^^^^ ->data : object -> : ^^^^^^ ->options : object -> : ^^^^^^ - - // Possible bug in original: createIntervalJobs can return undefined, but the original overload did not acount for that. - } - - throw new Error('Unexpected error: Invalid job name(s)'); ->new Error('Unexpected error: Invalid job name(s)') : Error -> : ^^^^^ ->Error : ErrorConstructor -> : ^^^^^^^^^^^^^^^^ ->'Unexpected error: Invalid job name(s)' : "Unexpected error: Invalid job name(s)" -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - } -} - -// File: angular/packages/common/src/pipes/case_conversion_pipes.ts - -function transform1<T extends string | null | undefined>(value: T): HelperCond<T, string, string, null | undefined, null> { ->transform1 : <T extends string | null | undefined>(value: T) => HelperCond<T, string, string, null | undefined, null> -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->value : T -> : ^ - - if (value == null) return null; // Ok ->value == null : boolean -> : ^^^^^^^ ->value : T -> : ^ - - if (typeof value !== 'string') { ->typeof value !== 'string' : boolean -> : ^^^^^^^ ->typeof value : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->value : NonNullable<T> -> : ^^^^^^^^^^^^^^ ->'string' : "string" -> : ^^^^^^^^ - - throw new Error(); ->new Error() : Error -> : ^^^^^ ->Error : ErrorConstructor -> : ^^^^^^^^^^^^^^^^ - } - return value.toLowerCase(); // Ok ->value.toLowerCase() : string -> : ^^^^^^ ->value.toLowerCase : () => string -> : ^^^^^^ ->value : string -> : ^^^^^^ ->toLowerCase : () => string -> : ^^^^^^ -} diff --git a/tests/baselines/reference/dependentReturnType4.errors.txt b/tests/baselines/reference/dependentReturnType4.errors.txt deleted file mode 100644 index 5f06601f9fe98..0000000000000 --- a/tests/baselines/reference/dependentReturnType4.errors.txt +++ /dev/null @@ -1,40 +0,0 @@ -dependentReturnType4.ts(28,9): error TS2322: Type '0' is not assignable to type 'T extends undefined ? 0 : T extends string ? 1 : never'. -dependentReturnType4.ts(30,5): error TS2322: Type '1' is not assignable to type 'T extends undefined ? 0 : T extends string ? 1 : never'. - - -==== dependentReturnType4.ts (2 errors) ==== - declare const rand: { a?: never }; - type Missing = typeof rand.a; - - // Detection of valid optional parameter references - - // Ok, will narrow return type - function bar1<T extends string | Missing>(x?: T): - T extends Missing ? 0 : T extends string ? 1 : never { - if (x === undefined) { - return 0; - } - return 1; - } - - // Ok, will narrow return type - function bar2<T extends string | undefined>(x?: T): - T extends undefined ? 0 : T extends string ? 1 : never { - if (x === undefined) { - return 0; - } - return 1; - } - - // Not ok, will not narrow return type - function bar3<T extends string>(x?: T): - T extends undefined ? 0 : T extends string ? 1 : never { - if (x === undefined) { - return 0; - ~~~~~~ -!!! error TS2322: Type '0' is not assignable to type 'T extends undefined ? 0 : T extends string ? 1 : never'. - } - return 1; - ~~~~~~ -!!! error TS2322: Type '1' is not assignable to type 'T extends undefined ? 0 : T extends string ? 1 : never'. - } \ No newline at end of file diff --git a/tests/baselines/reference/dependentReturnType4.symbols b/tests/baselines/reference/dependentReturnType4.symbols deleted file mode 100644 index 77b99a29dd972..0000000000000 --- a/tests/baselines/reference/dependentReturnType4.symbols +++ /dev/null @@ -1,76 +0,0 @@ -//// [tests/cases/compiler/dependentReturnType4.ts] //// - -=== dependentReturnType4.ts === -declare const rand: { a?: never }; ->rand : Symbol(rand, Decl(dependentReturnType4.ts, 0, 13)) ->a : Symbol(a, Decl(dependentReturnType4.ts, 0, 21)) - -type Missing = typeof rand.a; ->Missing : Symbol(Missing, Decl(dependentReturnType4.ts, 0, 34)) ->rand.a : Symbol(a, Decl(dependentReturnType4.ts, 0, 21)) ->rand : Symbol(rand, Decl(dependentReturnType4.ts, 0, 13)) ->a : Symbol(a, Decl(dependentReturnType4.ts, 0, 21)) - -// Detection of valid optional parameter references - -// Ok, will narrow return type -function bar1<T extends string | Missing>(x?: T): ->bar1 : Symbol(bar1, Decl(dependentReturnType4.ts, 1, 29)) ->T : Symbol(T, Decl(dependentReturnType4.ts, 6, 14)) ->Missing : Symbol(Missing, Decl(dependentReturnType4.ts, 0, 34)) ->x : Symbol(x, Decl(dependentReturnType4.ts, 6, 42)) ->T : Symbol(T, Decl(dependentReturnType4.ts, 6, 14)) - - T extends Missing ? 0 : T extends string ? 1 : never { ->T : Symbol(T, Decl(dependentReturnType4.ts, 6, 14)) ->Missing : Symbol(Missing, Decl(dependentReturnType4.ts, 0, 34)) ->T : Symbol(T, Decl(dependentReturnType4.ts, 6, 14)) - - if (x === undefined) { ->x : Symbol(x, Decl(dependentReturnType4.ts, 6, 42)) ->undefined : Symbol(undefined) - - return 0; - } - return 1; -} - -// Ok, will narrow return type -function bar2<T extends string | undefined>(x?: T): ->bar2 : Symbol(bar2, Decl(dependentReturnType4.ts, 12, 1)) ->T : Symbol(T, Decl(dependentReturnType4.ts, 15, 14)) ->x : Symbol(x, Decl(dependentReturnType4.ts, 15, 44)) ->T : Symbol(T, Decl(dependentReturnType4.ts, 15, 14)) - - T extends undefined ? 0 : T extends string ? 1 : never { ->T : Symbol(T, Decl(dependentReturnType4.ts, 15, 14)) ->T : Symbol(T, Decl(dependentReturnType4.ts, 15, 14)) - - if (x === undefined) { ->x : Symbol(x, Decl(dependentReturnType4.ts, 15, 44)) ->undefined : Symbol(undefined) - - return 0; - } - return 1; -} - -// Not ok, will not narrow return type -function bar3<T extends string>(x?: T): ->bar3 : Symbol(bar3, Decl(dependentReturnType4.ts, 21, 1)) ->T : Symbol(T, Decl(dependentReturnType4.ts, 24, 14)) ->x : Symbol(x, Decl(dependentReturnType4.ts, 24, 32)) ->T : Symbol(T, Decl(dependentReturnType4.ts, 24, 14)) - - T extends undefined ? 0 : T extends string ? 1 : never { ->T : Symbol(T, Decl(dependentReturnType4.ts, 24, 14)) ->T : Symbol(T, Decl(dependentReturnType4.ts, 24, 14)) - - if (x === undefined) { ->x : Symbol(x, Decl(dependentReturnType4.ts, 24, 32)) ->undefined : Symbol(undefined) - - return 0; - } - return 1; -} diff --git a/tests/baselines/reference/dependentReturnType4.types b/tests/baselines/reference/dependentReturnType4.types deleted file mode 100644 index 8b2b910a65fbb..0000000000000 --- a/tests/baselines/reference/dependentReturnType4.types +++ /dev/null @@ -1,95 +0,0 @@ -//// [tests/cases/compiler/dependentReturnType4.ts] //// - -=== dependentReturnType4.ts === -declare const rand: { a?: never }; ->rand : { a?: never; } -> : ^^^^^^ ^^^ ->a : undefined -> : ^^^^^^^^^ - -type Missing = typeof rand.a; ->Missing : undefined -> : ^^^^^^^^^ ->rand.a : undefined -> : ^^^^^^^^^ ->rand : { a?: never; } -> : ^^^^^^ ^^^ ->a : undefined -> : ^^^^^^^^^ - -// Detection of valid optional parameter references - -// Ok, will narrow return type -function bar1<T extends string | Missing>(x?: T): ->bar1 : <T extends string | Missing>(x?: T) => T extends Missing ? 0 : T extends string ? 1 : never -> : ^ ^^^^^^^^^ ^^ ^^^ ^^^^^ ->x : T | undefined -> : ^^^^^^^^^^^^^ - - T extends Missing ? 0 : T extends string ? 1 : never { - if (x === undefined) { ->x === undefined : boolean -> : ^^^^^^^ ->x : T | undefined -> : ^^^^^^^^^^^^^ ->undefined : undefined -> : ^^^^^^^^^ - - return 0; ->0 : 0 -> : ^ - } - return 1; ->1 : 1 -> : ^ -} - -// Ok, will narrow return type -function bar2<T extends string | undefined>(x?: T): ->bar2 : <T extends string | undefined>(x?: T) => T extends undefined ? 0 : T extends string ? 1 : never -> : ^ ^^^^^^^^^ ^^ ^^^ ^^^^^ ->x : T | undefined -> : ^^^^^^^^^^^^^ - - T extends undefined ? 0 : T extends string ? 1 : never { - if (x === undefined) { ->x === undefined : boolean -> : ^^^^^^^ ->x : T | undefined -> : ^^^^^^^^^^^^^ ->undefined : undefined -> : ^^^^^^^^^ - - return 0; ->0 : 0 -> : ^ - } - return 1; ->1 : 1 -> : ^ -} - -// Not ok, will not narrow return type -function bar3<T extends string>(x?: T): ->bar3 : <T extends string>(x?: T) => T extends undefined ? 0 : T extends string ? 1 : never -> : ^ ^^^^^^^^^ ^^ ^^^ ^^^^^ ->x : T | undefined -> : ^^^^^^^^^^^^^ - - T extends undefined ? 0 : T extends string ? 1 : never { - if (x === undefined) { ->x === undefined : boolean -> : ^^^^^^^ ->x : T | undefined -> : ^^^^^^^^^^^^^ ->undefined : undefined -> : ^^^^^^^^^ - - return 0; ->0 : 0 -> : ^ - } - return 1; ->1 : 1 -> : ^ -} diff --git a/tests/baselines/reference/dependentReturnType5.errors.txt b/tests/baselines/reference/dependentReturnType5.errors.txt deleted file mode 100644 index ce2ada8762c9b..0000000000000 --- a/tests/baselines/reference/dependentReturnType5.errors.txt +++ /dev/null @@ -1,109 +0,0 @@ -dependentReturnType5.ts(54,13): error TS2322: Type '2' is not assignable to type 'Comp[T]'. - Type '2' is not assignable to type '3'. -dependentReturnType5.ts(65,5): error TS2322: Type '2' is not assignable to type 'Comp[T]'. - Type '2' is not assignable to type '3'. - - -==== dependentReturnType5.ts (2 errors) ==== - // Indexed access return type - interface A1 { - "prop": true; - [s: string]: boolean; - } - - // This was already allowed but is unsound. - function foo1<T extends string>(x: T): A1[T] { - return false; - } - const rfoo1 = foo1("prop"); // Type says true, but actually returns false. - - interface A2 { - "prop": true; - [n: number]: string; - } - - // We could soundly allow that, because `"prop"` and `[n: number]` are disjoint types. - function foo2<T extends "prop" | number>(x: T): A2[T] { - if (x === "prop") { - return true; - } - return "some string"; - } - const rfoo2 = foo2("prop"); - const rfoo22 = foo2(34); - const rfoo222 = foo2(Math.random() ? "prop" : 34); - - interface A3 { - [s: string]: boolean; - } - - // No need for return type narrowing. - function foo3<T extends string>(x: T): A3[T] { - if (Math.random()) return true; - return false; - } - - interface Comp { - foo: 2; - [n: number]: 3; - [s: string]: 2 | 3 | 4; - } - - function indexedComp<T extends number | string>(x: T): Comp[T] { - if (x === "foo") { - if (Math.random()) { - return 3; // Error - } - return 2; // Ok - } - if (typeof x === "number") { - if (Math.random()) { - return 2; // Error - ~~~~~~ -!!! error TS2322: Type '2' is not assignable to type 'Comp[T]'. -!!! error TS2322: Type '2' is not assignable to type '3'. - } - return 3; // Ok - } - return 4; // Ok - } - - function indexedComp2<T extends number | string>(x: T): Comp[T] { - if (Math.random()) { - return 3; // Bad, unsound - } - return 2; // Error - ~~~~~~ -!!! error TS2322: Type '2' is not assignable to type 'Comp[T]'. -!!! error TS2322: Type '2' is not assignable to type '3'. - } - - - // Most common case supported: - interface F { - "t": number, - "f": boolean, - } - - // Ok - function depLikeFun<T extends "t" | "f">(str: T): F[T] { - if (str === "t") { - return 1; - } else { - return true; - } - } - - depLikeFun("t"); // has type number - depLikeFun("f"); // has type boolean - - type IndirectF<T extends keyof F> = F[T]; - - // Ok - function depLikeFun2<T extends "t" | "f">(str: T): IndirectF<T> { - if (str === "t") { - return 1; - } else { - return true; - } - } \ No newline at end of file diff --git a/tests/baselines/reference/dependentReturnType5.symbols b/tests/baselines/reference/dependentReturnType5.symbols deleted file mode 100644 index 9061f59ff0c12..0000000000000 --- a/tests/baselines/reference/dependentReturnType5.symbols +++ /dev/null @@ -1,220 +0,0 @@ -//// [tests/cases/compiler/dependentReturnType5.ts] //// - -=== dependentReturnType5.ts === -// Indexed access return type -interface A1 { ->A1 : Symbol(A1, Decl(dependentReturnType5.ts, 0, 0)) - - "prop": true; ->"prop" : Symbol(A1["prop"], Decl(dependentReturnType5.ts, 1, 14)) - - [s: string]: boolean; ->s : Symbol(s, Decl(dependentReturnType5.ts, 3, 5)) -} - -// This was already allowed but is unsound. -function foo1<T extends string>(x: T): A1[T] { ->foo1 : Symbol(foo1, Decl(dependentReturnType5.ts, 4, 1)) ->T : Symbol(T, Decl(dependentReturnType5.ts, 7, 14)) ->x : Symbol(x, Decl(dependentReturnType5.ts, 7, 32)) ->T : Symbol(T, Decl(dependentReturnType5.ts, 7, 14)) ->A1 : Symbol(A1, Decl(dependentReturnType5.ts, 0, 0)) ->T : Symbol(T, Decl(dependentReturnType5.ts, 7, 14)) - - return false; -} -const rfoo1 = foo1("prop"); // Type says true, but actually returns false. ->rfoo1 : Symbol(rfoo1, Decl(dependentReturnType5.ts, 10, 5)) ->foo1 : Symbol(foo1, Decl(dependentReturnType5.ts, 4, 1)) - -interface A2 { ->A2 : Symbol(A2, Decl(dependentReturnType5.ts, 10, 27)) - - "prop": true; ->"prop" : Symbol(A2["prop"], Decl(dependentReturnType5.ts, 12, 14)) - - [n: number]: string; ->n : Symbol(n, Decl(dependentReturnType5.ts, 14, 5)) -} - -// We could soundly allow that, because `"prop"` and `[n: number]` are disjoint types. -function foo2<T extends "prop" | number>(x: T): A2[T] { ->foo2 : Symbol(foo2, Decl(dependentReturnType5.ts, 15, 1)) ->T : Symbol(T, Decl(dependentReturnType5.ts, 18, 14)) ->x : Symbol(x, Decl(dependentReturnType5.ts, 18, 41)) ->T : Symbol(T, Decl(dependentReturnType5.ts, 18, 14)) ->A2 : Symbol(A2, Decl(dependentReturnType5.ts, 10, 27)) ->T : Symbol(T, Decl(dependentReturnType5.ts, 18, 14)) - - if (x === "prop") { ->x : Symbol(x, Decl(dependentReturnType5.ts, 18, 41)) - - return true; - } - return "some string"; -} -const rfoo2 = foo2("prop"); ->rfoo2 : Symbol(rfoo2, Decl(dependentReturnType5.ts, 24, 5)) ->foo2 : Symbol(foo2, Decl(dependentReturnType5.ts, 15, 1)) - -const rfoo22 = foo2(34); ->rfoo22 : Symbol(rfoo22, Decl(dependentReturnType5.ts, 25, 5)) ->foo2 : Symbol(foo2, Decl(dependentReturnType5.ts, 15, 1)) - -const rfoo222 = foo2(Math.random() ? "prop" : 34); ->rfoo222 : Symbol(rfoo222, Decl(dependentReturnType5.ts, 26, 5)) ->foo2 : Symbol(foo2, Decl(dependentReturnType5.ts, 15, 1)) ->Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) ->Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) ->random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) - -interface A3 { ->A3 : Symbol(A3, Decl(dependentReturnType5.ts, 26, 50)) - - [s: string]: boolean; ->s : Symbol(s, Decl(dependentReturnType5.ts, 29, 5)) -} - -// No need for return type narrowing. -function foo3<T extends string>(x: T): A3[T] { ->foo3 : Symbol(foo3, Decl(dependentReturnType5.ts, 30, 1)) ->T : Symbol(T, Decl(dependentReturnType5.ts, 33, 14)) ->x : Symbol(x, Decl(dependentReturnType5.ts, 33, 32)) ->T : Symbol(T, Decl(dependentReturnType5.ts, 33, 14)) ->A3 : Symbol(A3, Decl(dependentReturnType5.ts, 26, 50)) ->T : Symbol(T, Decl(dependentReturnType5.ts, 33, 14)) - - if (Math.random()) return true; ->Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) ->Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) ->random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) - - return false; -} - -interface Comp { ->Comp : Symbol(Comp, Decl(dependentReturnType5.ts, 36, 1)) - - foo: 2; ->foo : Symbol(Comp.foo, Decl(dependentReturnType5.ts, 38, 16)) - - [n: number]: 3; ->n : Symbol(n, Decl(dependentReturnType5.ts, 40, 5)) - - [s: string]: 2 | 3 | 4; ->s : Symbol(s, Decl(dependentReturnType5.ts, 41, 5)) -} - -function indexedComp<T extends number | string>(x: T): Comp[T] { ->indexedComp : Symbol(indexedComp, Decl(dependentReturnType5.ts, 42, 1)) ->T : Symbol(T, Decl(dependentReturnType5.ts, 44, 21)) ->x : Symbol(x, Decl(dependentReturnType5.ts, 44, 48)) ->T : Symbol(T, Decl(dependentReturnType5.ts, 44, 21)) ->Comp : Symbol(Comp, Decl(dependentReturnType5.ts, 36, 1)) ->T : Symbol(T, Decl(dependentReturnType5.ts, 44, 21)) - - if (x === "foo") { ->x : Symbol(x, Decl(dependentReturnType5.ts, 44, 48)) - - if (Math.random()) { ->Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) ->Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) ->random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) - - return 3; // Error - } - return 2; // Ok - } - if (typeof x === "number") { ->x : Symbol(x, Decl(dependentReturnType5.ts, 44, 48)) - - if (Math.random()) { ->Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) ->Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) ->random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) - - return 2; // Error - } - return 3; // Ok - } - return 4; // Ok -} - -function indexedComp2<T extends number | string>(x: T): Comp[T] { ->indexedComp2 : Symbol(indexedComp2, Decl(dependentReturnType5.ts, 58, 1)) ->T : Symbol(T, Decl(dependentReturnType5.ts, 60, 22)) ->x : Symbol(x, Decl(dependentReturnType5.ts, 60, 49)) ->T : Symbol(T, Decl(dependentReturnType5.ts, 60, 22)) ->Comp : Symbol(Comp, Decl(dependentReturnType5.ts, 36, 1)) ->T : Symbol(T, Decl(dependentReturnType5.ts, 60, 22)) - - if (Math.random()) { ->Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) ->Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) ->random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) - - return 3; // Bad, unsound - } - return 2; // Error -} - - -// Most common case supported: -interface F { ->F : Symbol(F, Decl(dependentReturnType5.ts, 65, 1)) - - "t": number, ->"t" : Symbol(F["t"], Decl(dependentReturnType5.ts, 69, 13)) - - "f": boolean, ->"f" : Symbol(F["f"], Decl(dependentReturnType5.ts, 70, 16)) -} - -// Ok -function depLikeFun<T extends "t" | "f">(str: T): F[T] { ->depLikeFun : Symbol(depLikeFun, Decl(dependentReturnType5.ts, 72, 1)) ->T : Symbol(T, Decl(dependentReturnType5.ts, 75, 20)) ->str : Symbol(str, Decl(dependentReturnType5.ts, 75, 41)) ->T : Symbol(T, Decl(dependentReturnType5.ts, 75, 20)) ->F : Symbol(F, Decl(dependentReturnType5.ts, 65, 1)) ->T : Symbol(T, Decl(dependentReturnType5.ts, 75, 20)) - - if (str === "t") { ->str : Symbol(str, Decl(dependentReturnType5.ts, 75, 41)) - - return 1; - } else { - return true; - } -} - -depLikeFun("t"); // has type number ->depLikeFun : Symbol(depLikeFun, Decl(dependentReturnType5.ts, 72, 1)) - -depLikeFun("f"); // has type boolean ->depLikeFun : Symbol(depLikeFun, Decl(dependentReturnType5.ts, 72, 1)) - -type IndirectF<T extends keyof F> = F[T]; ->IndirectF : Symbol(IndirectF, Decl(dependentReturnType5.ts, 84, 16)) ->T : Symbol(T, Decl(dependentReturnType5.ts, 86, 15)) ->F : Symbol(F, Decl(dependentReturnType5.ts, 65, 1)) ->F : Symbol(F, Decl(dependentReturnType5.ts, 65, 1)) ->T : Symbol(T, Decl(dependentReturnType5.ts, 86, 15)) - -// Ok -function depLikeFun2<T extends "t" | "f">(str: T): IndirectF<T> { ->depLikeFun2 : Symbol(depLikeFun2, Decl(dependentReturnType5.ts, 86, 41)) ->T : Symbol(T, Decl(dependentReturnType5.ts, 89, 21)) ->str : Symbol(str, Decl(dependentReturnType5.ts, 89, 42)) ->T : Symbol(T, Decl(dependentReturnType5.ts, 89, 21)) ->IndirectF : Symbol(IndirectF, Decl(dependentReturnType5.ts, 84, 16)) ->T : Symbol(T, Decl(dependentReturnType5.ts, 89, 21)) - - if (str === "t") { ->str : Symbol(str, Decl(dependentReturnType5.ts, 89, 42)) - - return 1; - } else { - return true; - } -} diff --git a/tests/baselines/reference/dependentReturnType5.types b/tests/baselines/reference/dependentReturnType5.types deleted file mode 100644 index 25f542fec56de..0000000000000 --- a/tests/baselines/reference/dependentReturnType5.types +++ /dev/null @@ -1,331 +0,0 @@ -//// [tests/cases/compiler/dependentReturnType5.ts] //// - -=== dependentReturnType5.ts === -// Indexed access return type -interface A1 { - "prop": true; ->"prop" : true -> : ^^^^ ->true : true -> : ^^^^ - - [s: string]: boolean; ->s : string -> : ^^^^^^ -} - -// This was already allowed but is unsound. -function foo1<T extends string>(x: T): A1[T] { ->foo1 : <T extends string>(x: T) => A1[T] -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->x : T -> : ^ - - return false; ->false : false -> : ^^^^^ -} -const rfoo1 = foo1("prop"); // Type says true, but actually returns false. ->rfoo1 : true -> : ^^^^ ->foo1("prop") : true -> : ^^^^ ->foo1 : <T extends string>(x: T) => A1[T] -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->"prop" : "prop" -> : ^^^^^^ - -interface A2 { - "prop": true; ->"prop" : true -> : ^^^^ ->true : true -> : ^^^^ - - [n: number]: string; ->n : number -> : ^^^^^^ -} - -// We could soundly allow that, because `"prop"` and `[n: number]` are disjoint types. -function foo2<T extends "prop" | number>(x: T): A2[T] { ->foo2 : <T extends "prop" | number>(x: T) => A2[T] -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->x : T -> : ^ - - if (x === "prop") { ->x === "prop" : boolean -> : ^^^^^^^ ->x : T -> : ^ ->"prop" : "prop" -> : ^^^^^^ - - return true; ->true : true -> : ^^^^ - } - return "some string"; ->"some string" : "some string" -> : ^^^^^^^^^^^^^ -} -const rfoo2 = foo2("prop"); ->rfoo2 : true -> : ^^^^ ->foo2("prop") : true -> : ^^^^ ->foo2 : <T extends "prop" | number>(x: T) => A2[T] -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->"prop" : "prop" -> : ^^^^^^ - -const rfoo22 = foo2(34); ->rfoo22 : string -> : ^^^^^^ ->foo2(34) : string -> : ^^^^^^ ->foo2 : <T extends "prop" | number>(x: T) => A2[T] -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->34 : 34 -> : ^^ - -const rfoo222 = foo2(Math.random() ? "prop" : 34); ->rfoo222 : string | true -> : ^^^^^^^^^^^^^ ->foo2(Math.random() ? "prop" : 34) : string | true -> : ^^^^^^^^^^^^^ ->foo2 : <T extends "prop" | number>(x: T) => A2[T] -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->Math.random() ? "prop" : 34 : "prop" | 34 -> : ^^^^^^^^^^^ ->Math.random() : number -> : ^^^^^^ ->Math.random : () => number -> : ^^^^^^ ->Math : Math -> : ^^^^ ->random : () => number -> : ^^^^^^ ->"prop" : "prop" -> : ^^^^^^ ->34 : 34 -> : ^^ - -interface A3 { - [s: string]: boolean; ->s : string -> : ^^^^^^ -} - -// No need for return type narrowing. -function foo3<T extends string>(x: T): A3[T] { ->foo3 : <T extends string>(x: T) => A3[T] -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->x : T -> : ^ - - if (Math.random()) return true; ->Math.random() : number -> : ^^^^^^ ->Math.random : () => number -> : ^^^^^^ ->Math : Math -> : ^^^^ ->random : () => number -> : ^^^^^^ ->true : true -> : ^^^^ - - return false; ->false : false -> : ^^^^^ -} - -interface Comp { - foo: 2; ->foo : 2 -> : ^ - - [n: number]: 3; ->n : number -> : ^^^^^^ - - [s: string]: 2 | 3 | 4; ->s : string -> : ^^^^^^ -} - -function indexedComp<T extends number | string>(x: T): Comp[T] { ->indexedComp : <T extends number | string>(x: T) => Comp[T] -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->x : T -> : ^ - - if (x === "foo") { ->x === "foo" : boolean -> : ^^^^^^^ ->x : T -> : ^ ->"foo" : "foo" -> : ^^^^^ - - if (Math.random()) { ->Math.random() : number -> : ^^^^^^ ->Math.random : () => number -> : ^^^^^^ ->Math : Math -> : ^^^^ ->random : () => number -> : ^^^^^^ - - return 3; // Error ->3 : 3 -> : ^ - } - return 2; // Ok ->2 : 2 -> : ^ - } - if (typeof x === "number") { ->typeof x === "number" : boolean -> : ^^^^^^^ ->typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->x : T -> : ^ ->"number" : "number" -> : ^^^^^^^^ - - if (Math.random()) { ->Math.random() : number -> : ^^^^^^ ->Math.random : () => number -> : ^^^^^^ ->Math : Math -> : ^^^^ ->random : () => number -> : ^^^^^^ - - return 2; // Error ->2 : 2 -> : ^ - } - return 3; // Ok ->3 : 3 -> : ^ - } - return 4; // Ok ->4 : 4 -> : ^ -} - -function indexedComp2<T extends number | string>(x: T): Comp[T] { ->indexedComp2 : <T extends number | string>(x: T) => Comp[T] -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->x : T -> : ^ - - if (Math.random()) { ->Math.random() : number -> : ^^^^^^ ->Math.random : () => number -> : ^^^^^^ ->Math : Math -> : ^^^^ ->random : () => number -> : ^^^^^^ - - return 3; // Bad, unsound ->3 : 3 -> : ^ - } - return 2; // Error ->2 : 2 -> : ^ -} - - -// Most common case supported: -interface F { - "t": number, ->"t" : number -> : ^^^^^^ - - "f": boolean, ->"f" : boolean -> : ^^^^^^^ -} - -// Ok -function depLikeFun<T extends "t" | "f">(str: T): F[T] { ->depLikeFun : <T extends "t" | "f">(str: T) => F[T] -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->str : T -> : ^ - - if (str === "t") { ->str === "t" : boolean -> : ^^^^^^^ ->str : T -> : ^ ->"t" : "t" -> : ^^^ - - return 1; ->1 : 1 -> : ^ - - } else { - return true; ->true : true -> : ^^^^ - } -} - -depLikeFun("t"); // has type number ->depLikeFun("t") : number -> : ^^^^^^ ->depLikeFun : <T extends "t" | "f">(str: T) => F[T] -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->"t" : "t" -> : ^^^ - -depLikeFun("f"); // has type boolean ->depLikeFun("f") : boolean -> : ^^^^^^^ ->depLikeFun : <T extends "t" | "f">(str: T) => F[T] -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->"f" : "f" -> : ^^^ - -type IndirectF<T extends keyof F> = F[T]; ->IndirectF : IndirectF<T> -> : ^^^^^^^^^^^^ - -// Ok -function depLikeFun2<T extends "t" | "f">(str: T): IndirectF<T> { ->depLikeFun2 : <T extends "t" | "f">(str: T) => IndirectF<T> -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->str : T -> : ^ - - if (str === "t") { ->str === "t" : boolean -> : ^^^^^^^ ->str : T -> : ^ ->"t" : "t" -> : ^^^ - - return 1; ->1 : 1 -> : ^ - - } else { - return true; ->true : true -> : ^^^^ - } -} diff --git a/tests/baselines/reference/dependentReturnType6.errors.txt b/tests/baselines/reference/dependentReturnType6.errors.txt deleted file mode 100644 index 638c23268ad80..0000000000000 --- a/tests/baselines/reference/dependentReturnType6.errors.txt +++ /dev/null @@ -1,193 +0,0 @@ -file.ts(28,26): error TS2322: Type 'true' is not assignable to type 'SomeInterfaceBad<T>[U]'. - Type 'true' is not assignable to type 'T extends 1 ? true : T extends 2 ? false : never'. -file.ts(28,33): error TS2322: Type 'false' is not assignable to type 'SomeInterfaceBad<T>[U]'. - Type 'false' is not assignable to type 'T extends 1 ? true : T extends 2 ? false : never'. -file.ts(30,16): error TS2322: Type '1' is not assignable to type 'SomeInterfaceBad<T>[U]'. - Type '1' is not assignable to type 'T extends true ? 1 : T extends false ? 2 : never'. -file.ts(30,20): error TS2322: Type '2' is not assignable to type 'SomeInterfaceBad<T>[U]'. - Type '2' is not assignable to type 'T extends true ? 1 : T extends false ? 2 : never'. -file.ts(80,13): error TS2322: Type '1' is not assignable to type 'this extends Sub1 ? 1 : this extends Sub2 ? 2 : never'. -file.ts(82,9): error TS2322: Type '2' is not assignable to type 'this extends Sub1 ? 1 : this extends Sub2 ? 2 : never'. -file.ts(94,16): error TS2322: Type '1' is not assignable to type 'T extends true ? 1 : T extends false ? 2 : never'. -file.ts(94,20): error TS2322: Type '2' is not assignable to type 'T extends true ? 1 : T extends false ? 2 : never'. -file.ts(98,100): error TS2322: Type '1 | 2' is not assignable to type 'T extends true ? 1 : T extends false ? 2 : never'. - Type '1' is not assignable to type 'T extends true ? 1 : T extends false ? 2 : never'. -file.ts(106,9): error TS2322: Type 'number' is not assignable to type 'SomeCond<T>'. -file.ts(106,9): error TS2589: Type instantiation is excessively deep and possibly infinite. -file.ts(108,5): error TS2322: Type 'number' is not assignable to type 'SomeCond<T>'. -file.ts(114,60): error TS2366: Function lacks ending return statement and return type does not include 'undefined'. -file.ts(116,9): error TS2322: Type '"one"' is not assignable to type 'OtherCond<U> | OtherCond<V>'. -file.ts(126,9): error TS2322: Type '"a"' is not assignable to type 'T extends (infer P)[] ? P : T extends number ? undefined : never'. -file.ts(128,5): error TS2322: Type 'undefined' is not assignable to type 'T extends (infer P)[] ? P : T extends number ? undefined : never'. - - -==== file.ts (16 errors) ==== - // Type parameter in outer scope - function outer<T extends boolean>(x: T): number { - return inner(); - - function inner(): T extends true ? 1 : T extends false ? 2 : never { - return x ? 1 : 2; - } - } - - // Overloads - function fun6<T extends boolean>(x: T, y: string): T extends true ? string : T extends false ? 2 : never; - function fun6<T extends boolean>(x: T, y: undefined): T extends true ? 1 : T extends false ? 2 : never; - function fun6(x: boolean): 1 | 2 | string; - function fun6<T extends boolean>(x: T, y?: string): T extends true ? 1 | string : T extends false ? 2 : never { - return x ? y !== undefined ? y : 1 : 2; - } - - // Indexed access with conditional inside - - // DOESN'T NARROW the nested conditional type of wrong shape - interface SomeInterfaceBad<T> { - prop1: T extends 1 ? true : T extends 2 ? false : never; - prop2: T extends true ? 1 : T extends false ? 2 : never; - } - - function fun4bad<T, U extends keyof SomeInterfaceBad<unknown>>(x: T, y: U): SomeInterfaceBad<T>[U] { - if (y === "prop1") { - return x === 1 ? true : false; - ~~~~ -!!! error TS2322: Type 'true' is not assignable to type 'SomeInterfaceBad<T>[U]'. -!!! error TS2322: Type 'true' is not assignable to type 'T extends 1 ? true : T extends 2 ? false : never'. - ~~~~~ -!!! error TS2322: Type 'false' is not assignable to type 'SomeInterfaceBad<T>[U]'. -!!! error TS2322: Type 'false' is not assignable to type 'T extends 1 ? true : T extends 2 ? false : never'. - } - return x ? 1 : 2; - ~ -!!! error TS2322: Type '1' is not assignable to type 'SomeInterfaceBad<T>[U]'. -!!! error TS2322: Type '1' is not assignable to type 'T extends true ? 1 : T extends false ? 2 : never'. - ~ -!!! error TS2322: Type '2' is not assignable to type 'SomeInterfaceBad<T>[U]'. -!!! error TS2322: Type '2' is not assignable to type 'T extends true ? 1 : T extends false ? 2 : never'. - } - - // Narrows nested conditional type of right shape - interface SomeInterfaceGood<T> { - prop1: T extends true ? 2 : T extends false ? 1 : never; - prop2: T extends true ? 1 : T extends false ? 2 : never; - } - - function fun4good<T extends boolean, U extends keyof SomeInterfaceGood<unknown>>(x: T, y: U): SomeInterfaceGood<T>[U] { - if (y === "prop1") { - return x ? 2 : 1; - } - return x ? 1 : 2; - } - - // Indexed access with indexed access inside - OK, narrows - interface BB { - "a": number; - "b": string; - } - - interface AA<T extends keyof BB> { - "c": BB[T]; - "d": boolean, - } - - function reduction<T extends keyof BB, U extends keyof AA<any>>(x: T, y: U): AA<T>[U] { - if (x === "a" && y === "c") { - return 0; // Ok - } - - return undefined as never; - } - - // Conditional with indexed access inside - OK, narrows - function fun5<T extends 1 | 2, U extends keyof BB>(x: T, y: U): T extends 1 ? BB[U] : T extends 2 ? boolean : never { - if (x === 1) { - if (y === "a") { - return 0; - } - return ""; - } - return true; - } - - // `this` type parameter - Doesn't narrow - abstract class SomeClass { - fun3(this: Sub1 | Sub2): this extends Sub1 ? 1 : this extends Sub2 ? 2 : never { - if (this instanceof Sub1) { - return 1; - ~~~~~~ -!!! error TS2322: Type '1' is not assignable to type 'this extends Sub1 ? 1 : this extends Sub2 ? 2 : never'. - } - return 2; - ~~~~~~ -!!! error TS2322: Type '2' is not assignable to type 'this extends Sub1 ? 1 : this extends Sub2 ? 2 : never'. - } - } - class Sub1 extends SomeClass { - #sub1!: symbol; - }; - class Sub2 extends SomeClass { - #sub2!: symbol; - }; - - // Detection of type parameter reference in presence of typeof - function fun2<T extends boolean>(x: T, y: typeof x): T extends true ? 1 : T extends false ? 2 : never { - return x ? 1 : 2; - ~ -!!! error TS2322: Type '1' is not assignable to type 'T extends true ? 1 : T extends false ? 2 : never'. - ~ -!!! error TS2322: Type '2' is not assignable to type 'T extends true ? 1 : T extends false ? 2 : never'. - } - - // Contextually-typed lambdas - const fun1: <T extends boolean>(x: T) => T extends true ? 1 : T extends false ? 2 : never = (x) => x ? 1 : 2; - ~~~~~~~~~ -!!! error TS2322: Type '1 | 2' is not assignable to type 'T extends true ? 1 : T extends false ? 2 : never'. -!!! error TS2322: Type '1' is not assignable to type 'T extends true ? 1 : T extends false ? 2 : never'. -!!! related TS6502 file.ts:98:13: The expected type comes from the return type of this signature. - - - // Circular conditionals - type SomeCond<T> = T extends true ? 1 : T extends false ? SomeCond<T> : never; - - function f7<T extends boolean>(x: T): SomeCond<T> { - if (x) { - return 1; - ~~~~~~ -!!! error TS2322: Type 'number' is not assignable to type 'SomeCond<T>'. - ~~~~~~ -!!! error TS2589: Type instantiation is excessively deep and possibly infinite. - } - return 2; - ~~~~~~ -!!! error TS2322: Type 'number' is not assignable to type 'SomeCond<T>'. - } - - // Composite instantiation of conditional type - type OtherCond<T> = T extends 1 ? "one" : T extends 2 ? "two" : T extends 3 ? "three" : T extends 4 ? "four" : never; - - function f8<U extends 1 | 2, V extends 3 | 4>(x: U, y: V): OtherCond<U | V> { - ~~~~~~~~~~~~~~~~ -!!! error TS2366: Function lacks ending return statement and return type does not include 'undefined'. - if (x === 1 && y === 3) { - return "one"; - ~~~~~~ -!!! error TS2322: Type '"one"' is not assignable to type 'OtherCond<U> | OtherCond<V>'. - } - } - - // Conditionals with `infer` - will not narrow, it is not safe to infer from the narrowed type into an `infer` type parameter - function f9<T extends "a"[] | "b"[] | number>(x: T): T extends Array<infer P> ? P : T extends number ? undefined : never { - if (Array.isArray(x)) { - // If we allowed narrowing of the conditional return type, when resolving the conditional `T & ("a"[] | "b"[]) extends Array<infer P> ? P : ...`, - // we could infer `"a" | "b"` for `P`, and allow "a" to be returned. However, when calling `f10`, `T` could be instantiated with `"b"[]`, and the return type would be `"b"`, - // so allowing an `"a"` return would be unsound. - return "a"; - ~~~~~~ -!!! error TS2322: Type '"a"' is not assignable to type 'T extends (infer P)[] ? P : T extends number ? undefined : never'. - } - return undefined; - ~~~~~~ -!!! error TS2322: Type 'undefined' is not assignable to type 'T extends (infer P)[] ? P : T extends number ? undefined : never'. - } - - \ No newline at end of file diff --git a/tests/baselines/reference/dependentReturnType6.symbols b/tests/baselines/reference/dependentReturnType6.symbols deleted file mode 100644 index 44fc28739e099..0000000000000 --- a/tests/baselines/reference/dependentReturnType6.symbols +++ /dev/null @@ -1,367 +0,0 @@ -//// [tests/cases/compiler/dependentReturnType6.ts] //// - -=== file.ts === -// Type parameter in outer scope -function outer<T extends boolean>(x: T): number { ->outer : Symbol(outer, Decl(file.ts, 0, 0)) ->T : Symbol(T, Decl(file.ts, 1, 15)) ->x : Symbol(x, Decl(file.ts, 1, 34)) ->T : Symbol(T, Decl(file.ts, 1, 15)) - - return inner(); ->inner : Symbol(inner, Decl(file.ts, 2, 19)) - - function inner(): T extends true ? 1 : T extends false ? 2 : never { ->inner : Symbol(inner, Decl(file.ts, 2, 19)) ->T : Symbol(T, Decl(file.ts, 1, 15)) ->T : Symbol(T, Decl(file.ts, 1, 15)) - - return x ? 1 : 2; ->x : Symbol(x, Decl(file.ts, 1, 34)) - } -} - -// Overloads -function fun6<T extends boolean>(x: T, y: string): T extends true ? string : T extends false ? 2 : never; ->fun6 : Symbol(fun6, Decl(file.ts, 7, 1), Decl(file.ts, 10, 105), Decl(file.ts, 11, 103), Decl(file.ts, 12, 42)) ->T : Symbol(T, Decl(file.ts, 10, 14)) ->x : Symbol(x, Decl(file.ts, 10, 33)) ->T : Symbol(T, Decl(file.ts, 10, 14)) ->y : Symbol(y, Decl(file.ts, 10, 38)) ->T : Symbol(T, Decl(file.ts, 10, 14)) ->T : Symbol(T, Decl(file.ts, 10, 14)) - -function fun6<T extends boolean>(x: T, y: undefined): T extends true ? 1 : T extends false ? 2 : never; ->fun6 : Symbol(fun6, Decl(file.ts, 7, 1), Decl(file.ts, 10, 105), Decl(file.ts, 11, 103), Decl(file.ts, 12, 42)) ->T : Symbol(T, Decl(file.ts, 11, 14)) ->x : Symbol(x, Decl(file.ts, 11, 33)) ->T : Symbol(T, Decl(file.ts, 11, 14)) ->y : Symbol(y, Decl(file.ts, 11, 38)) ->T : Symbol(T, Decl(file.ts, 11, 14)) ->T : Symbol(T, Decl(file.ts, 11, 14)) - -function fun6(x: boolean): 1 | 2 | string; ->fun6 : Symbol(fun6, Decl(file.ts, 7, 1), Decl(file.ts, 10, 105), Decl(file.ts, 11, 103), Decl(file.ts, 12, 42)) ->x : Symbol(x, Decl(file.ts, 12, 14)) - -function fun6<T extends boolean>(x: T, y?: string): T extends true ? 1 | string : T extends false ? 2 : never { ->fun6 : Symbol(fun6, Decl(file.ts, 7, 1), Decl(file.ts, 10, 105), Decl(file.ts, 11, 103), Decl(file.ts, 12, 42)) ->T : Symbol(T, Decl(file.ts, 13, 14)) ->x : Symbol(x, Decl(file.ts, 13, 33)) ->T : Symbol(T, Decl(file.ts, 13, 14)) ->y : Symbol(y, Decl(file.ts, 13, 38)) ->T : Symbol(T, Decl(file.ts, 13, 14)) ->T : Symbol(T, Decl(file.ts, 13, 14)) - - return x ? y !== undefined ? y : 1 : 2; ->x : Symbol(x, Decl(file.ts, 13, 33)) ->y : Symbol(y, Decl(file.ts, 13, 38)) ->undefined : Symbol(undefined) ->y : Symbol(y, Decl(file.ts, 13, 38)) -} - -// Indexed access with conditional inside - -// DOESN'T NARROW the nested conditional type of wrong shape -interface SomeInterfaceBad<T> { ->SomeInterfaceBad : Symbol(SomeInterfaceBad, Decl(file.ts, 15, 1)) ->T : Symbol(T, Decl(file.ts, 20, 27)) - - prop1: T extends 1 ? true : T extends 2 ? false : never; ->prop1 : Symbol(SomeInterfaceBad.prop1, Decl(file.ts, 20, 31)) ->T : Symbol(T, Decl(file.ts, 20, 27)) ->T : Symbol(T, Decl(file.ts, 20, 27)) - - prop2: T extends true ? 1 : T extends false ? 2 : never; ->prop2 : Symbol(SomeInterfaceBad.prop2, Decl(file.ts, 21, 60)) ->T : Symbol(T, Decl(file.ts, 20, 27)) ->T : Symbol(T, Decl(file.ts, 20, 27)) -} - -function fun4bad<T, U extends keyof SomeInterfaceBad<unknown>>(x: T, y: U): SomeInterfaceBad<T>[U] { ->fun4bad : Symbol(fun4bad, Decl(file.ts, 23, 1)) ->T : Symbol(T, Decl(file.ts, 25, 17)) ->U : Symbol(U, Decl(file.ts, 25, 19)) ->SomeInterfaceBad : Symbol(SomeInterfaceBad, Decl(file.ts, 15, 1)) ->x : Symbol(x, Decl(file.ts, 25, 63)) ->T : Symbol(T, Decl(file.ts, 25, 17)) ->y : Symbol(y, Decl(file.ts, 25, 68)) ->U : Symbol(U, Decl(file.ts, 25, 19)) ->SomeInterfaceBad : Symbol(SomeInterfaceBad, Decl(file.ts, 15, 1)) ->T : Symbol(T, Decl(file.ts, 25, 17)) ->U : Symbol(U, Decl(file.ts, 25, 19)) - - if (y === "prop1") { ->y : Symbol(y, Decl(file.ts, 25, 68)) - - return x === 1 ? true : false; ->x : Symbol(x, Decl(file.ts, 25, 63)) - } - return x ? 1 : 2; ->x : Symbol(x, Decl(file.ts, 25, 63)) -} - -// Narrows nested conditional type of right shape -interface SomeInterfaceGood<T> { ->SomeInterfaceGood : Symbol(SomeInterfaceGood, Decl(file.ts, 30, 1)) ->T : Symbol(T, Decl(file.ts, 33, 28)) - - prop1: T extends true ? 2 : T extends false ? 1 : never; ->prop1 : Symbol(SomeInterfaceGood.prop1, Decl(file.ts, 33, 32)) ->T : Symbol(T, Decl(file.ts, 33, 28)) ->T : Symbol(T, Decl(file.ts, 33, 28)) - - prop2: T extends true ? 1 : T extends false ? 2 : never; ->prop2 : Symbol(SomeInterfaceGood.prop2, Decl(file.ts, 34, 60)) ->T : Symbol(T, Decl(file.ts, 33, 28)) ->T : Symbol(T, Decl(file.ts, 33, 28)) -} - -function fun4good<T extends boolean, U extends keyof SomeInterfaceGood<unknown>>(x: T, y: U): SomeInterfaceGood<T>[U] { ->fun4good : Symbol(fun4good, Decl(file.ts, 36, 1)) ->T : Symbol(T, Decl(file.ts, 38, 18)) ->U : Symbol(U, Decl(file.ts, 38, 36)) ->SomeInterfaceGood : Symbol(SomeInterfaceGood, Decl(file.ts, 30, 1)) ->x : Symbol(x, Decl(file.ts, 38, 81)) ->T : Symbol(T, Decl(file.ts, 38, 18)) ->y : Symbol(y, Decl(file.ts, 38, 86)) ->U : Symbol(U, Decl(file.ts, 38, 36)) ->SomeInterfaceGood : Symbol(SomeInterfaceGood, Decl(file.ts, 30, 1)) ->T : Symbol(T, Decl(file.ts, 38, 18)) ->U : Symbol(U, Decl(file.ts, 38, 36)) - - if (y === "prop1") { ->y : Symbol(y, Decl(file.ts, 38, 86)) - - return x ? 2 : 1; ->x : Symbol(x, Decl(file.ts, 38, 81)) - } - return x ? 1 : 2; ->x : Symbol(x, Decl(file.ts, 38, 81)) -} - -// Indexed access with indexed access inside - OK, narrows -interface BB { ->BB : Symbol(BB, Decl(file.ts, 43, 1)) - - "a": number; ->"a" : Symbol(BB["a"], Decl(file.ts, 46, 14)) - - "b": string; ->"b" : Symbol(BB["b"], Decl(file.ts, 47, 16)) -} - -interface AA<T extends keyof BB> { ->AA : Symbol(AA, Decl(file.ts, 49, 1)) ->T : Symbol(T, Decl(file.ts, 51, 13)) ->BB : Symbol(BB, Decl(file.ts, 43, 1)) - - "c": BB[T]; ->"c" : Symbol(AA["c"], Decl(file.ts, 51, 34)) ->BB : Symbol(BB, Decl(file.ts, 43, 1)) ->T : Symbol(T, Decl(file.ts, 51, 13)) - - "d": boolean, ->"d" : Symbol(AA["d"], Decl(file.ts, 52, 15)) -} - -function reduction<T extends keyof BB, U extends keyof AA<any>>(x: T, y: U): AA<T>[U] { ->reduction : Symbol(reduction, Decl(file.ts, 54, 1)) ->T : Symbol(T, Decl(file.ts, 56, 19)) ->BB : Symbol(BB, Decl(file.ts, 43, 1)) ->U : Symbol(U, Decl(file.ts, 56, 38)) ->AA : Symbol(AA, Decl(file.ts, 49, 1)) ->x : Symbol(x, Decl(file.ts, 56, 64)) ->T : Symbol(T, Decl(file.ts, 56, 19)) ->y : Symbol(y, Decl(file.ts, 56, 69)) ->U : Symbol(U, Decl(file.ts, 56, 38)) ->AA : Symbol(AA, Decl(file.ts, 49, 1)) ->T : Symbol(T, Decl(file.ts, 56, 19)) ->U : Symbol(U, Decl(file.ts, 56, 38)) - - if (x === "a" && y === "c") { ->x : Symbol(x, Decl(file.ts, 56, 64)) ->y : Symbol(y, Decl(file.ts, 56, 69)) - - return 0; // Ok - } - - return undefined as never; ->undefined : Symbol(undefined) -} - -// Conditional with indexed access inside - OK, narrows -function fun5<T extends 1 | 2, U extends keyof BB>(x: T, y: U): T extends 1 ? BB[U] : T extends 2 ? boolean : never { ->fun5 : Symbol(fun5, Decl(file.ts, 62, 1)) ->T : Symbol(T, Decl(file.ts, 65, 14)) ->U : Symbol(U, Decl(file.ts, 65, 30)) ->BB : Symbol(BB, Decl(file.ts, 43, 1)) ->x : Symbol(x, Decl(file.ts, 65, 51)) ->T : Symbol(T, Decl(file.ts, 65, 14)) ->y : Symbol(y, Decl(file.ts, 65, 56)) ->U : Symbol(U, Decl(file.ts, 65, 30)) ->T : Symbol(T, Decl(file.ts, 65, 14)) ->BB : Symbol(BB, Decl(file.ts, 43, 1)) ->U : Symbol(U, Decl(file.ts, 65, 30)) ->T : Symbol(T, Decl(file.ts, 65, 14)) - - if (x === 1) { ->x : Symbol(x, Decl(file.ts, 65, 51)) - - if (y === "a") { ->y : Symbol(y, Decl(file.ts, 65, 56)) - - return 0; - } - return ""; - } - return true; -} - -// `this` type parameter - Doesn't narrow -abstract class SomeClass { ->SomeClass : Symbol(SomeClass, Decl(file.ts, 73, 1)) - - fun3(this: Sub1 | Sub2): this extends Sub1 ? 1 : this extends Sub2 ? 2 : never { ->fun3 : Symbol(SomeClass.fun3, Decl(file.ts, 76, 26)) ->this : Symbol(this, Decl(file.ts, 77, 9)) ->Sub1 : Symbol(Sub1, Decl(file.ts, 83, 1)) ->Sub2 : Symbol(Sub2, Decl(file.ts, 86, 2)) ->Sub1 : Symbol(Sub1, Decl(file.ts, 83, 1)) ->Sub2 : Symbol(Sub2, Decl(file.ts, 86, 2)) - - if (this instanceof Sub1) { ->this : Symbol(this, Decl(file.ts, 77, 9)) ->Sub1 : Symbol(Sub1, Decl(file.ts, 83, 1)) - - return 1; - } - return 2; - } -} -class Sub1 extends SomeClass { ->Sub1 : Symbol(Sub1, Decl(file.ts, 83, 1)) ->SomeClass : Symbol(SomeClass, Decl(file.ts, 73, 1)) - - #sub1!: symbol; ->#sub1 : Symbol(Sub1.#sub1, Decl(file.ts, 84, 30)) - -}; -class Sub2 extends SomeClass { ->Sub2 : Symbol(Sub2, Decl(file.ts, 86, 2)) ->SomeClass : Symbol(SomeClass, Decl(file.ts, 73, 1)) - - #sub2!: symbol; ->#sub2 : Symbol(Sub2.#sub2, Decl(file.ts, 87, 30)) - -}; - -// Detection of type parameter reference in presence of typeof -function fun2<T extends boolean>(x: T, y: typeof x): T extends true ? 1 : T extends false ? 2 : never { ->fun2 : Symbol(fun2, Decl(file.ts, 89, 2)) ->T : Symbol(T, Decl(file.ts, 92, 14)) ->x : Symbol(x, Decl(file.ts, 92, 33)) ->T : Symbol(T, Decl(file.ts, 92, 14)) ->y : Symbol(y, Decl(file.ts, 92, 38)) ->x : Symbol(x, Decl(file.ts, 92, 33)) ->T : Symbol(T, Decl(file.ts, 92, 14)) ->T : Symbol(T, Decl(file.ts, 92, 14)) - - return x ? 1 : 2; ->x : Symbol(x, Decl(file.ts, 92, 33)) -} - -// Contextually-typed lambdas -const fun1: <T extends boolean>(x: T) => T extends true ? 1 : T extends false ? 2 : never = (x) => x ? 1 : 2; ->fun1 : Symbol(fun1, Decl(file.ts, 97, 5)) ->T : Symbol(T, Decl(file.ts, 97, 13)) ->x : Symbol(x, Decl(file.ts, 97, 32)) ->T : Symbol(T, Decl(file.ts, 97, 13)) ->T : Symbol(T, Decl(file.ts, 97, 13)) ->T : Symbol(T, Decl(file.ts, 97, 13)) ->x : Symbol(x, Decl(file.ts, 97, 93)) ->x : Symbol(x, Decl(file.ts, 97, 93)) - - -// Circular conditionals -type SomeCond<T> = T extends true ? 1 : T extends false ? SomeCond<T> : never; ->SomeCond : Symbol(SomeCond, Decl(file.ts, 97, 109)) ->T : Symbol(T, Decl(file.ts, 101, 14)) ->T : Symbol(T, Decl(file.ts, 101, 14)) ->T : Symbol(T, Decl(file.ts, 101, 14)) ->SomeCond : Symbol(SomeCond, Decl(file.ts, 97, 109)) ->T : Symbol(T, Decl(file.ts, 101, 14)) - -function f7<T extends boolean>(x: T): SomeCond<T> { ->f7 : Symbol(f7, Decl(file.ts, 101, 78)) ->T : Symbol(T, Decl(file.ts, 103, 12)) ->x : Symbol(x, Decl(file.ts, 103, 31)) ->T : Symbol(T, Decl(file.ts, 103, 12)) ->SomeCond : Symbol(SomeCond, Decl(file.ts, 97, 109)) ->T : Symbol(T, Decl(file.ts, 103, 12)) - - if (x) { ->x : Symbol(x, Decl(file.ts, 103, 31)) - - return 1; - } - return 2; -} - -// Composite instantiation of conditional type -type OtherCond<T> = T extends 1 ? "one" : T extends 2 ? "two" : T extends 3 ? "three" : T extends 4 ? "four" : never; ->OtherCond : Symbol(OtherCond, Decl(file.ts, 108, 1)) ->T : Symbol(T, Decl(file.ts, 111, 15)) ->T : Symbol(T, Decl(file.ts, 111, 15)) ->T : Symbol(T, Decl(file.ts, 111, 15)) ->T : Symbol(T, Decl(file.ts, 111, 15)) ->T : Symbol(T, Decl(file.ts, 111, 15)) - -function f8<U extends 1 | 2, V extends 3 | 4>(x: U, y: V): OtherCond<U | V> { ->f8 : Symbol(f8, Decl(file.ts, 111, 117)) ->U : Symbol(U, Decl(file.ts, 113, 12)) ->V : Symbol(V, Decl(file.ts, 113, 28)) ->x : Symbol(x, Decl(file.ts, 113, 46)) ->U : Symbol(U, Decl(file.ts, 113, 12)) ->y : Symbol(y, Decl(file.ts, 113, 51)) ->V : Symbol(V, Decl(file.ts, 113, 28)) ->OtherCond : Symbol(OtherCond, Decl(file.ts, 108, 1)) ->U : Symbol(U, Decl(file.ts, 113, 12)) ->V : Symbol(V, Decl(file.ts, 113, 28)) - - if (x === 1 && y === 3) { ->x : Symbol(x, Decl(file.ts, 113, 46)) ->y : Symbol(y, Decl(file.ts, 113, 51)) - - return "one"; - } -} - -// Conditionals with `infer` - will not narrow, it is not safe to infer from the narrowed type into an `infer` type parameter -function f9<T extends "a"[] | "b"[] | number>(x: T): T extends Array<infer P> ? P : T extends number ? undefined : never { ->f9 : Symbol(f9, Decl(file.ts, 117, 1)) ->T : Symbol(T, Decl(file.ts, 120, 12)) ->x : Symbol(x, Decl(file.ts, 120, 46)) ->T : Symbol(T, Decl(file.ts, 120, 12)) ->T : Symbol(T, Decl(file.ts, 120, 12)) ->Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 4 more) ->P : Symbol(P, Decl(file.ts, 120, 74)) ->P : Symbol(P, Decl(file.ts, 120, 74)) ->T : Symbol(T, Decl(file.ts, 120, 12)) - - if (Array.isArray(x)) { ->Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) ->Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 4 more) ->isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) ->x : Symbol(x, Decl(file.ts, 120, 46)) - - // If we allowed narrowing of the conditional return type, when resolving the conditional `T & ("a"[] | "b"[]) extends Array<infer P> ? P : ...`, - // we could infer `"a" | "b"` for `P`, and allow "a" to be returned. However, when calling `f10`, `T` could be instantiated with `"b"[]`, and the return type would be `"b"`, - // so allowing an `"a"` return would be unsound. - return "a"; - } - return undefined; ->undefined : Symbol(undefined) -} - - diff --git a/tests/baselines/reference/dependentReturnType6.types b/tests/baselines/reference/dependentReturnType6.types deleted file mode 100644 index f1831992e691f..0000000000000 --- a/tests/baselines/reference/dependentReturnType6.types +++ /dev/null @@ -1,512 +0,0 @@ -//// [tests/cases/compiler/dependentReturnType6.ts] //// - -=== Performance Stats === -Instantiation count: 5,000 - -=== file.ts === -// Type parameter in outer scope -function outer<T extends boolean>(x: T): number { ->outer : <T extends boolean>(x: T) => number -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->x : T -> : ^ - - return inner(); ->inner() : T extends true ? 1 : T extends false ? 2 : never -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->inner : () => T extends true ? 1 : T extends false ? 2 : never -> : ^^^^^^ - - function inner(): T extends true ? 1 : T extends false ? 2 : never { ->inner : () => T extends true ? 1 : T extends false ? 2 : never -> : ^^^^^^ ->true : true -> : ^^^^ ->false : false -> : ^^^^^ - - return x ? 1 : 2; ->x ? 1 : 2 : 1 | 2 -> : ^^^^^ ->x : T -> : ^ ->1 : 1 -> : ^ ->2 : 2 -> : ^ - } -} - -// Overloads -function fun6<T extends boolean>(x: T, y: string): T extends true ? string : T extends false ? 2 : never; ->fun6 : { <T extends boolean>(x: T, y: string): T extends true ? string : T extends false ? 2 : never; <T_1 extends boolean>(x: T_1, y: undefined): T_1 extends true ? 1 : T_1 extends false ? 2 : never; (x: boolean): 1 | 2 | string; } -> : ^^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^ ^^^^^^^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^ ^^^ ^^ ^^^ ^^^ ->x : T -> : ^ ->y : string -> : ^^^^^^ ->true : true -> : ^^^^ ->false : false -> : ^^^^^ - -function fun6<T extends boolean>(x: T, y: undefined): T extends true ? 1 : T extends false ? 2 : never; ->fun6 : { <T_1 extends boolean>(x: T_1, y: string): T_1 extends true ? string : T_1 extends false ? 2 : never; <T extends boolean>(x: T, y: undefined): T extends true ? 1 : T extends false ? 2 : never; (x: boolean): 1 | 2 | string; } -> : ^^^^^^^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^ ^^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^ ^^^ ^^ ^^^ ^^^ ->x : T -> : ^ ->y : undefined -> : ^^^^^^^^^ ->true : true -> : ^^^^ ->false : false -> : ^^^^^ - -function fun6(x: boolean): 1 | 2 | string; ->fun6 : { <T extends boolean>(x: T, y: string): T extends true ? string : T extends false ? 2 : never; <T extends boolean>(x: T, y: undefined): T extends true ? 1 : T extends false ? 2 : never; (x: boolean): 1 | 2 | string; } -> : ^^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^ ^^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^ ^^^ ^^ ^^^ ^^^ ->x : boolean -> : ^^^^^^^ - -function fun6<T extends boolean>(x: T, y?: string): T extends true ? 1 | string : T extends false ? 2 : never { ->fun6 : { <T_1 extends boolean>(x: T_1, y: string): T_1 extends true ? string : T_1 extends false ? 2 : never; <T_1 extends boolean>(x: T_1, y: undefined): T_1 extends true ? 1 : T_1 extends false ? 2 : never; (x: boolean): 1 | 2 | string; } -> : ^^^^^^^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^ ^^^^^^^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^ ^^^ ^^ ^^^ ^^^ ->x : T -> : ^ ->y : string | undefined -> : ^^^^^^^^^^^^^^^^^^ ->true : true -> : ^^^^ ->false : false -> : ^^^^^ - - return x ? y !== undefined ? y : 1 : 2; ->x ? y !== undefined ? y : 1 : 2 : string | 1 | 2 -> : ^^^^^^^^^^^^^^ ->x : T -> : ^ ->y !== undefined ? y : 1 : string | 1 -> : ^^^^^^^^^^ ->y !== undefined : boolean -> : ^^^^^^^ ->y : string | undefined -> : ^^^^^^^^^^^^^^^^^^ ->undefined : undefined -> : ^^^^^^^^^ ->y : string -> : ^^^^^^ ->1 : 1 -> : ^ ->2 : 2 -> : ^ -} - -// Indexed access with conditional inside - -// DOESN'T NARROW the nested conditional type of wrong shape -interface SomeInterfaceBad<T> { - prop1: T extends 1 ? true : T extends 2 ? false : never; ->prop1 : T extends 1 ? true : T extends 2 ? false : never -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->true : true -> : ^^^^ ->false : false -> : ^^^^^ - - prop2: T extends true ? 1 : T extends false ? 2 : never; ->prop2 : T extends true ? 1 : T extends false ? 2 : never -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->true : true -> : ^^^^ ->false : false -> : ^^^^^ -} - -function fun4bad<T, U extends keyof SomeInterfaceBad<unknown>>(x: T, y: U): SomeInterfaceBad<T>[U] { ->fun4bad : <T, U extends keyof SomeInterfaceBad<unknown>>(x: T, y: U) => SomeInterfaceBad<T>[U] -> : ^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^ ->x : T -> : ^ ->y : U -> : ^ - - if (y === "prop1") { ->y === "prop1" : boolean -> : ^^^^^^^ ->y : U -> : ^ ->"prop1" : "prop1" -> : ^^^^^^^ - - return x === 1 ? true : false; ->x === 1 ? true : false : boolean -> : ^^^^^^^ ->x === 1 : boolean -> : ^^^^^^^ ->x : T -> : ^ ->1 : 1 -> : ^ ->true : true -> : ^^^^ ->false : false -> : ^^^^^ - } - return x ? 1 : 2; ->x ? 1 : 2 : 1 | 2 -> : ^^^^^ ->x : T -> : ^ ->1 : 1 -> : ^ ->2 : 2 -> : ^ -} - -// Narrows nested conditional type of right shape -interface SomeInterfaceGood<T> { - prop1: T extends true ? 2 : T extends false ? 1 : never; ->prop1 : T extends true ? 2 : T extends false ? 1 : never -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->true : true -> : ^^^^ ->false : false -> : ^^^^^ - - prop2: T extends true ? 1 : T extends false ? 2 : never; ->prop2 : T extends true ? 1 : T extends false ? 2 : never -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->true : true -> : ^^^^ ->false : false -> : ^^^^^ -} - -function fun4good<T extends boolean, U extends keyof SomeInterfaceGood<unknown>>(x: T, y: U): SomeInterfaceGood<T>[U] { ->fun4good : <T extends boolean, U extends keyof SomeInterfaceGood<unknown>>(x: T, y: U) => SomeInterfaceGood<T>[U] -> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^ ->x : T -> : ^ ->y : U -> : ^ - - if (y === "prop1") { ->y === "prop1" : boolean -> : ^^^^^^^ ->y : U -> : ^ ->"prop1" : "prop1" -> : ^^^^^^^ - - return x ? 2 : 1; ->x ? 2 : 1 : 1 | 2 -> : ^^^^^ ->x : T -> : ^ ->2 : 2 -> : ^ ->1 : 1 -> : ^ - } - return x ? 1 : 2; ->x ? 1 : 2 : 1 | 2 -> : ^^^^^ ->x : T -> : ^ ->1 : 1 -> : ^ ->2 : 2 -> : ^ -} - -// Indexed access with indexed access inside - OK, narrows -interface BB { - "a": number; ->"a" : number -> : ^^^^^^ - - "b": string; ->"b" : string -> : ^^^^^^ -} - -interface AA<T extends keyof BB> { - "c": BB[T]; ->"c" : BB[T] -> : ^^^^^ - - "d": boolean, ->"d" : boolean -> : ^^^^^^^ -} - -function reduction<T extends keyof BB, U extends keyof AA<any>>(x: T, y: U): AA<T>[U] { ->reduction : <T extends keyof BB, U extends keyof AA<any>>(x: T, y: U) => AA<T>[U] -> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^ ->x : T -> : ^ ->y : U -> : ^ - - if (x === "a" && y === "c") { ->x === "a" && y === "c" : boolean -> : ^^^^^^^ ->x === "a" : boolean -> : ^^^^^^^ ->x : T -> : ^ ->"a" : "a" -> : ^^^ ->y === "c" : boolean -> : ^^^^^^^ ->y : U -> : ^ ->"c" : "c" -> : ^^^ - - return 0; // Ok ->0 : 0 -> : ^ - } - - return undefined as never; ->undefined as never : never -> : ^^^^^ ->undefined : undefined -> : ^^^^^^^^^ -} - -// Conditional with indexed access inside - OK, narrows -function fun5<T extends 1 | 2, U extends keyof BB>(x: T, y: U): T extends 1 ? BB[U] : T extends 2 ? boolean : never { ->fun5 : <T extends 1 | 2, U extends keyof BB>(x: T, y: U) => T extends 1 ? BB[U] : T extends 2 ? boolean : never -> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^ ->x : T -> : ^ ->y : U -> : ^ - - if (x === 1) { ->x === 1 : boolean -> : ^^^^^^^ ->x : T -> : ^ ->1 : 1 -> : ^ - - if (y === "a") { ->y === "a" : boolean -> : ^^^^^^^ ->y : U -> : ^ ->"a" : "a" -> : ^^^ - - return 0; ->0 : 0 -> : ^ - } - return ""; ->"" : "" -> : ^^ - } - return true; ->true : true -> : ^^^^ -} - -// `this` type parameter - Doesn't narrow -abstract class SomeClass { ->SomeClass : SomeClass -> : ^^^^^^^^^ - - fun3(this: Sub1 | Sub2): this extends Sub1 ? 1 : this extends Sub2 ? 2 : never { ->fun3 : (this: Sub1 | Sub2) => this extends Sub1 ? 1 : this extends Sub2 ? 2 : never -> : ^ ^^ ^^^^^ ->this : Sub1 | Sub2 -> : ^^^^^^^^^^^ - - if (this instanceof Sub1) { ->this instanceof Sub1 : boolean -> : ^^^^^^^ ->this : Sub1 | Sub2 -> : ^^^^^^^^^^^ ->Sub1 : typeof Sub1 -> : ^^^^^^^^^^^ - - return 1; ->1 : 1 -> : ^ - } - return 2; ->2 : 2 -> : ^ - } -} -class Sub1 extends SomeClass { ->Sub1 : Sub1 -> : ^^^^ ->SomeClass : SomeClass -> : ^^^^^^^^^ - - #sub1!: symbol; ->#sub1 : symbol -> : ^^^^^^ - -}; -class Sub2 extends SomeClass { ->Sub2 : Sub2 -> : ^^^^ ->SomeClass : SomeClass -> : ^^^^^^^^^ - - #sub2!: symbol; ->#sub2 : symbol -> : ^^^^^^ - -}; - -// Detection of type parameter reference in presence of typeof -function fun2<T extends boolean>(x: T, y: typeof x): T extends true ? 1 : T extends false ? 2 : never { ->fun2 : <T extends boolean>(x: T, y: typeof x) => T extends true ? 1 : T extends false ? 2 : never -> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^ ->x : T -> : ^ ->y : T -> : ^ ->x : T -> : ^ ->true : true -> : ^^^^ ->false : false -> : ^^^^^ - - return x ? 1 : 2; ->x ? 1 : 2 : 1 | 2 -> : ^^^^^ ->x : T -> : ^ ->1 : 1 -> : ^ ->2 : 2 -> : ^ -} - -// Contextually-typed lambdas -const fun1: <T extends boolean>(x: T) => T extends true ? 1 : T extends false ? 2 : never = (x) => x ? 1 : 2; ->fun1 : <T extends boolean>(x: T) => T extends true ? 1 : T extends false ? 2 : never -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->x : T -> : ^ ->true : true -> : ^^^^ ->false : false -> : ^^^^^ ->(x) => x ? 1 : 2 : <T extends boolean>(x: T) => 1 | 2 -> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^^^^^ ->x : T -> : ^ ->x ? 1 : 2 : 1 | 2 -> : ^^^^^ ->x : T -> : ^ ->1 : 1 -> : ^ ->2 : 2 -> : ^ - - -// Circular conditionals -type SomeCond<T> = T extends true ? 1 : T extends false ? SomeCond<T> : never; ->SomeCond : SomeCond<T> -> : ^^^^^^^^^^^ ->true : true -> : ^^^^ ->false : false -> : ^^^^^ - -function f7<T extends boolean>(x: T): SomeCond<T> { ->f7 : <T extends boolean>(x: T) => SomeCond<T> -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->x : T -> : ^ - - if (x) { ->x : T -> : ^ - - return 1; ->1 : 1 -> : ^ - } - return 2; ->2 : 2 -> : ^ -} - -// Composite instantiation of conditional type -type OtherCond<T> = T extends 1 ? "one" : T extends 2 ? "two" : T extends 3 ? "three" : T extends 4 ? "four" : never; ->OtherCond : OtherCond<T> -> : ^^^^^^^^^^^^ - -function f8<U extends 1 | 2, V extends 3 | 4>(x: U, y: V): OtherCond<U | V> { ->f8 : <U extends 1 | 2, V extends 3 | 4>(x: U, y: V) => OtherCond<U | V> -> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^^^^ ->x : U -> : ^ ->y : V -> : ^ - - if (x === 1 && y === 3) { ->x === 1 && y === 3 : boolean -> : ^^^^^^^ ->x === 1 : boolean -> : ^^^^^^^ ->x : U -> : ^ ->1 : 1 -> : ^ ->y === 3 : boolean -> : ^^^^^^^ ->y : V -> : ^ ->3 : 3 -> : ^ - - return "one"; ->"one" : "one" -> : ^^^^^ - } -} - -// Conditionals with `infer` - will not narrow, it is not safe to infer from the narrowed type into an `infer` type parameter -function f9<T extends "a"[] | "b"[] | number>(x: T): T extends Array<infer P> ? P : T extends number ? undefined : never { ->f9 : <T extends "a"[] | "b"[] | number>(x: T) => T extends Array<infer P> ? P : T extends number ? undefined : never -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->x : T -> : ^ - - if (Array.isArray(x)) { ->Array.isArray(x) : boolean -> : ^^^^^^^ ->Array.isArray : (arg: any) => arg is any[] -> : ^ ^^ ^^^^^ ->Array : ArrayConstructor -> : ^^^^^^^^^^^^^^^^ ->isArray : (arg: any) => arg is any[] -> : ^ ^^ ^^^^^ ->x : number | "a"[] | "b"[] -> : ^^^^^^^^^^^^^^^^^^^^^^ - - // If we allowed narrowing of the conditional return type, when resolving the conditional `T & ("a"[] | "b"[]) extends Array<infer P> ? P : ...`, - // we could infer `"a" | "b"` for `P`, and allow "a" to be returned. However, when calling `f10`, `T` could be instantiated with `"b"[]`, and the return type would be `"b"`, - // so allowing an `"a"` return would be unsound. - return "a"; ->"a" : "a" -> : ^^^ - } - return undefined; ->undefined : undefined -> : ^^^^^^^^^ -} - - diff --git a/tests/baselines/reference/dependentReturnType8.symbols b/tests/baselines/reference/dependentReturnType8.symbols deleted file mode 100644 index 9151c3c4dde80..0000000000000 --- a/tests/baselines/reference/dependentReturnType8.symbols +++ /dev/null @@ -1,30 +0,0 @@ -//// [tests/cases/compiler/dependentReturnType8.ts] //// - -=== dependentReturnType8.ts === -export {}; - -declare const record: Record<string, string[]>; ->record : Symbol(record, Decl(dependentReturnType8.ts, 2, 13)) ->Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) - -declare const array: string[]; ->array : Symbol(array, Decl(dependentReturnType8.ts, 3, 13)) - -// Arrow function with expression body -const getObject = ->getObject : Symbol(getObject, Decl(dependentReturnType8.ts, 6, 5)) - - <T extends string | undefined>(group: T): T extends string ? string[] : T extends undefined ? Record<string, string[]> : never => ->T : Symbol(T, Decl(dependentReturnType8.ts, 7, 5)) ->group : Symbol(group, Decl(dependentReturnType8.ts, 7, 35)) ->T : Symbol(T, Decl(dependentReturnType8.ts, 7, 5)) ->T : Symbol(T, Decl(dependentReturnType8.ts, 7, 5)) ->T : Symbol(T, Decl(dependentReturnType8.ts, 7, 5)) ->Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) - - group === undefined ? record : array; ->group : Symbol(group, Decl(dependentReturnType8.ts, 7, 35)) ->undefined : Symbol(undefined) ->record : Symbol(record, Decl(dependentReturnType8.ts, 2, 13)) ->array : Symbol(array, Decl(dependentReturnType8.ts, 3, 13)) - diff --git a/tests/baselines/reference/dependentReturnType8.types b/tests/baselines/reference/dependentReturnType8.types deleted file mode 100644 index c42a8b0bccb77..0000000000000 --- a/tests/baselines/reference/dependentReturnType8.types +++ /dev/null @@ -1,38 +0,0 @@ -//// [tests/cases/compiler/dependentReturnType8.ts] //// - -=== dependentReturnType8.ts === -export {}; - -declare const record: Record<string, string[]>; ->record : Record<string, string[]> -> : ^^^^^^^^^^^^^^^^^^^^^^^^ - -declare const array: string[]; ->array : string[] -> : ^^^^^^^^ - -// Arrow function with expression body -const getObject = ->getObject : <T extends string | undefined>(group: T) => T extends string ? string[] : T extends undefined ? Record<string, string[]> : never -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ - - <T extends string | undefined>(group: T): T extends string ? string[] : T extends undefined ? Record<string, string[]> : never => -><T extends string | undefined>(group: T): T extends string ? string[] : T extends undefined ? Record<string, string[]> : never => group === undefined ? record : array : <T extends string | undefined>(group: T) => T extends string ? string[] : T extends undefined ? Record<string, string[]> : never -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ ->group : T -> : ^ - - group === undefined ? record : array; ->group === undefined ? record : array : string[] | Record<string, string[]> -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->group === undefined : boolean -> : ^^^^^^^ ->group : T -> : ^ ->undefined : undefined -> : ^^^^^^^^^ ->record : Record<string, string[]> -> : ^^^^^^^^^^^^^^^^^^^^^^^^ ->array : string[] -> : ^^^^^^^^ - diff --git a/tests/baselines/reference/dependentReturnType9.errors.txt b/tests/baselines/reference/dependentReturnType9.errors.txt deleted file mode 100644 index da12eeaab2eb4..0000000000000 --- a/tests/baselines/reference/dependentReturnType9.errors.txt +++ /dev/null @@ -1,71 +0,0 @@ -dependentReturnType9.ts(57,4): error TS2366: Function lacks ending return statement and return type does not include 'undefined'. - - -==== dependentReturnType9.ts (1 errors) ==== - type Payload = - | { _tag: "auth"; username: string; password: string } - | { _tag: "cart"; items: Array<{ id: string; quantity: number }> } - | { _tag: "person"; name: string; age: number }; - - type PayloadContent = { - [P in Payload as P["_tag"]]: Omit<P, "_tag">; - }; - - // ok, exhaustive cases and default case with throw - function mockPayload<P_TAG extends Payload["_tag"]>( - str: P_TAG, - ): PayloadContent[P_TAG] { - switch (str) { - case "auth": - return { username: "test", password: "admin" }; - case "cart": - return { items: [{ id: "123", quantity: 123 }] }; - case "person": - return { name: "andrea", age: 27 }; - default: - throw new Error("unknown tag"); - } - } - - // ok, non-exhaustive cases but default case with throw - function mockPayload2<P_TAG extends Payload["_tag"]>( - str: P_TAG, - ): PayloadContent[P_TAG] { - switch (str) { - case "auth": - return { username: "test", password: "admin" }; - case "cart": - return { items: [{ id: "123", quantity: 123 }] }; - default: - throw new Error("unhandled tag"); - } - } - - // ok, exhaustive cases - function mockPayload3<P_TAG extends Payload["_tag"]>( - str: P_TAG, - ): PayloadContent[P_TAG] { - switch (str) { - case "auth": - return { username: "test", password: "admin" }; - case "cart": - return { items: [{ id: "123", quantity: 123 }] }; - case "person": - return { name: "andrea", age: 27 }; - } - } - - // error, non-exhaustive cases - function mockPayload4<P_TAG extends Payload["_tag"]>( - str: P_TAG, - ): PayloadContent[P_TAG] { - ~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2366: Function lacks ending return statement and return type does not include 'undefined'. - switch (str) { - case "auth": - return { username: "test", password: "admin" }; - case "cart": - return { items: [{ id: "123", quantity: 123 }] }; - } - } - \ No newline at end of file diff --git a/tests/baselines/reference/dependentReturnType9.symbols b/tests/baselines/reference/dependentReturnType9.symbols deleted file mode 100644 index d66bb2d76f040..0000000000000 --- a/tests/baselines/reference/dependentReturnType9.symbols +++ /dev/null @@ -1,173 +0,0 @@ -//// [tests/cases/compiler/dependentReturnType9.ts] //// - -=== dependentReturnType9.ts === -type Payload = ->Payload : Symbol(Payload, Decl(dependentReturnType9.ts, 0, 0)) - - | { _tag: "auth"; username: string; password: string } ->_tag : Symbol(_tag, Decl(dependentReturnType9.ts, 1, 5)) ->username : Symbol(username, Decl(dependentReturnType9.ts, 1, 19)) ->password : Symbol(password, Decl(dependentReturnType9.ts, 1, 37)) - - | { _tag: "cart"; items: Array<{ id: string; quantity: number }> } ->_tag : Symbol(_tag, Decl(dependentReturnType9.ts, 2, 5)) ->items : Symbol(items, Decl(dependentReturnType9.ts, 2, 19)) ->Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) ->id : Symbol(id, Decl(dependentReturnType9.ts, 2, 34)) ->quantity : Symbol(quantity, Decl(dependentReturnType9.ts, 2, 46)) - - | { _tag: "person"; name: string; age: number }; ->_tag : Symbol(_tag, Decl(dependentReturnType9.ts, 3, 5)) ->name : Symbol(name, Decl(dependentReturnType9.ts, 3, 21)) ->age : Symbol(age, Decl(dependentReturnType9.ts, 3, 35)) - -type PayloadContent = { ->PayloadContent : Symbol(PayloadContent, Decl(dependentReturnType9.ts, 3, 50)) - - [P in Payload as P["_tag"]]: Omit<P, "_tag">; ->P : Symbol(P, Decl(dependentReturnType9.ts, 6, 3)) ->Payload : Symbol(Payload, Decl(dependentReturnType9.ts, 0, 0)) ->P : Symbol(P, Decl(dependentReturnType9.ts, 6, 3)) ->Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --)) ->P : Symbol(P, Decl(dependentReturnType9.ts, 6, 3)) - -}; - -// ok, exhaustive cases and default case with throw -function mockPayload<P_TAG extends Payload["_tag"]>( ->mockPayload : Symbol(mockPayload, Decl(dependentReturnType9.ts, 7, 2)) ->P_TAG : Symbol(P_TAG, Decl(dependentReturnType9.ts, 10, 21)) ->Payload : Symbol(Payload, Decl(dependentReturnType9.ts, 0, 0)) - - str: P_TAG, ->str : Symbol(str, Decl(dependentReturnType9.ts, 10, 52)) ->P_TAG : Symbol(P_TAG, Decl(dependentReturnType9.ts, 10, 21)) - -): PayloadContent[P_TAG] { ->PayloadContent : Symbol(PayloadContent, Decl(dependentReturnType9.ts, 3, 50)) ->P_TAG : Symbol(P_TAG, Decl(dependentReturnType9.ts, 10, 21)) - - switch (str) { ->str : Symbol(str, Decl(dependentReturnType9.ts, 10, 52)) - - case "auth": - return { username: "test", password: "admin" }; ->username : Symbol(username, Decl(dependentReturnType9.ts, 15, 14)) ->password : Symbol(password, Decl(dependentReturnType9.ts, 15, 32)) - - case "cart": - return { items: [{ id: "123", quantity: 123 }] }; ->items : Symbol(items, Decl(dependentReturnType9.ts, 17, 14)) ->id : Symbol(id, Decl(dependentReturnType9.ts, 17, 24)) ->quantity : Symbol(quantity, Decl(dependentReturnType9.ts, 17, 35)) - - case "person": - return { name: "andrea", age: 27 }; ->name : Symbol(name, Decl(dependentReturnType9.ts, 19, 14)) ->age : Symbol(age, Decl(dependentReturnType9.ts, 19, 30)) - - default: - throw new Error("unknown tag"); ->Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) - } -} - -// ok, non-exhaustive cases but default case with throw -function mockPayload2<P_TAG extends Payload["_tag"]>( ->mockPayload2 : Symbol(mockPayload2, Decl(dependentReturnType9.ts, 23, 1)) ->P_TAG : Symbol(P_TAG, Decl(dependentReturnType9.ts, 26, 22)) ->Payload : Symbol(Payload, Decl(dependentReturnType9.ts, 0, 0)) - - str: P_TAG, ->str : Symbol(str, Decl(dependentReturnType9.ts, 26, 53)) ->P_TAG : Symbol(P_TAG, Decl(dependentReturnType9.ts, 26, 22)) - -): PayloadContent[P_TAG] { ->PayloadContent : Symbol(PayloadContent, Decl(dependentReturnType9.ts, 3, 50)) ->P_TAG : Symbol(P_TAG, Decl(dependentReturnType9.ts, 26, 22)) - - switch (str) { ->str : Symbol(str, Decl(dependentReturnType9.ts, 26, 53)) - - case "auth": - return { username: "test", password: "admin" }; ->username : Symbol(username, Decl(dependentReturnType9.ts, 31, 14)) ->password : Symbol(password, Decl(dependentReturnType9.ts, 31, 32)) - - case "cart": - return { items: [{ id: "123", quantity: 123 }] }; ->items : Symbol(items, Decl(dependentReturnType9.ts, 33, 14)) ->id : Symbol(id, Decl(dependentReturnType9.ts, 33, 24)) ->quantity : Symbol(quantity, Decl(dependentReturnType9.ts, 33, 35)) - - default: - throw new Error("unhandled tag"); ->Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) - } -} - -// ok, exhaustive cases -function mockPayload3<P_TAG extends Payload["_tag"]>( ->mockPayload3 : Symbol(mockPayload3, Decl(dependentReturnType9.ts, 37, 1)) ->P_TAG : Symbol(P_TAG, Decl(dependentReturnType9.ts, 40, 22)) ->Payload : Symbol(Payload, Decl(dependentReturnType9.ts, 0, 0)) - - str: P_TAG, ->str : Symbol(str, Decl(dependentReturnType9.ts, 40, 53)) ->P_TAG : Symbol(P_TAG, Decl(dependentReturnType9.ts, 40, 22)) - -): PayloadContent[P_TAG] { ->PayloadContent : Symbol(PayloadContent, Decl(dependentReturnType9.ts, 3, 50)) ->P_TAG : Symbol(P_TAG, Decl(dependentReturnType9.ts, 40, 22)) - - switch (str) { ->str : Symbol(str, Decl(dependentReturnType9.ts, 40, 53)) - - case "auth": - return { username: "test", password: "admin" }; ->username : Symbol(username, Decl(dependentReturnType9.ts, 45, 14)) ->password : Symbol(password, Decl(dependentReturnType9.ts, 45, 32)) - - case "cart": - return { items: [{ id: "123", quantity: 123 }] }; ->items : Symbol(items, Decl(dependentReturnType9.ts, 47, 14)) ->id : Symbol(id, Decl(dependentReturnType9.ts, 47, 24)) ->quantity : Symbol(quantity, Decl(dependentReturnType9.ts, 47, 35)) - - case "person": - return { name: "andrea", age: 27 }; ->name : Symbol(name, Decl(dependentReturnType9.ts, 49, 14)) ->age : Symbol(age, Decl(dependentReturnType9.ts, 49, 30)) - } -} - -// error, non-exhaustive cases -function mockPayload4<P_TAG extends Payload["_tag"]>( ->mockPayload4 : Symbol(mockPayload4, Decl(dependentReturnType9.ts, 51, 1)) ->P_TAG : Symbol(P_TAG, Decl(dependentReturnType9.ts, 54, 22)) ->Payload : Symbol(Payload, Decl(dependentReturnType9.ts, 0, 0)) - - str: P_TAG, ->str : Symbol(str, Decl(dependentReturnType9.ts, 54, 53)) ->P_TAG : Symbol(P_TAG, Decl(dependentReturnType9.ts, 54, 22)) - -): PayloadContent[P_TAG] { ->PayloadContent : Symbol(PayloadContent, Decl(dependentReturnType9.ts, 3, 50)) ->P_TAG : Symbol(P_TAG, Decl(dependentReturnType9.ts, 54, 22)) - - switch (str) { ->str : Symbol(str, Decl(dependentReturnType9.ts, 54, 53)) - - case "auth": - return { username: "test", password: "admin" }; ->username : Symbol(username, Decl(dependentReturnType9.ts, 59, 14)) ->password : Symbol(password, Decl(dependentReturnType9.ts, 59, 32)) - - case "cart": - return { items: [{ id: "123", quantity: 123 }] }; ->items : Symbol(items, Decl(dependentReturnType9.ts, 61, 14)) ->id : Symbol(id, Decl(dependentReturnType9.ts, 61, 24)) ->quantity : Symbol(quantity, Decl(dependentReturnType9.ts, 61, 35)) - } -} - diff --git a/tests/baselines/reference/dependentReturnType9.types b/tests/baselines/reference/dependentReturnType9.types deleted file mode 100644 index 834e5f578388b..0000000000000 --- a/tests/baselines/reference/dependentReturnType9.types +++ /dev/null @@ -1,306 +0,0 @@ -//// [tests/cases/compiler/dependentReturnType9.ts] //// - -=== dependentReturnType9.ts === -type Payload = ->Payload : Payload -> : ^^^^^^^ - - | { _tag: "auth"; username: string; password: string } ->_tag : "auth" -> : ^^^^^^ ->username : string -> : ^^^^^^ ->password : string -> : ^^^^^^ - - | { _tag: "cart"; items: Array<{ id: string; quantity: number }> } ->_tag : "cart" -> : ^^^^^^ ->items : { id: string; quantity: number; }[] -> : ^^^^^^ ^^^^^^^^^^^^ ^^^^^ ->id : string -> : ^^^^^^ ->quantity : number -> : ^^^^^^ - - | { _tag: "person"; name: string; age: number }; ->_tag : "person" -> : ^^^^^^^^ ->name : string -> : ^^^^^^ ->age : number -> : ^^^^^^ - -type PayloadContent = { ->PayloadContent : PayloadContent -> : ^^^^^^^^^^^^^^ - - [P in Payload as P["_tag"]]: Omit<P, "_tag">; -}; - -// ok, exhaustive cases and default case with throw -function mockPayload<P_TAG extends Payload["_tag"]>( ->mockPayload : <P_TAG extends Payload["_tag"]>(str: P_TAG) => PayloadContent[P_TAG] -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ - - str: P_TAG, ->str : P_TAG -> : ^^^^^ - -): PayloadContent[P_TAG] { - switch (str) { ->str : P_TAG -> : ^^^^^ - - case "auth": ->"auth" : "auth" -> : ^^^^^^ - - return { username: "test", password: "admin" }; ->{ username: "test", password: "admin" } : { username: string; password: string; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->username : string -> : ^^^^^^ ->"test" : "test" -> : ^^^^^^ ->password : string -> : ^^^^^^ ->"admin" : "admin" -> : ^^^^^^^ - - case "cart": ->"cart" : "cart" -> : ^^^^^^ - - return { items: [{ id: "123", quantity: 123 }] }; ->{ items: [{ id: "123", quantity: 123 }] } : { items: { id: string; quantity: number; }[]; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->items : { id: string; quantity: number; }[] -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->[{ id: "123", quantity: 123 }] : { id: string; quantity: number; }[] -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->{ id: "123", quantity: 123 } : { id: string; quantity: number; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->id : string -> : ^^^^^^ ->"123" : "123" -> : ^^^^^ ->quantity : number -> : ^^^^^^ ->123 : 123 -> : ^^^ - - case "person": ->"person" : "person" -> : ^^^^^^^^ - - return { name: "andrea", age: 27 }; ->{ name: "andrea", age: 27 } : { name: string; age: number; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->name : string -> : ^^^^^^ ->"andrea" : "andrea" -> : ^^^^^^^^ ->age : number -> : ^^^^^^ ->27 : 27 -> : ^^ - - default: - throw new Error("unknown tag"); ->new Error("unknown tag") : Error -> : ^^^^^ ->Error : ErrorConstructor -> : ^^^^^^^^^^^^^^^^ ->"unknown tag" : "unknown tag" -> : ^^^^^^^^^^^^^ - } -} - -// ok, non-exhaustive cases but default case with throw -function mockPayload2<P_TAG extends Payload["_tag"]>( ->mockPayload2 : <P_TAG extends Payload["_tag"]>(str: P_TAG) => PayloadContent[P_TAG] -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ - - str: P_TAG, ->str : P_TAG -> : ^^^^^ - -): PayloadContent[P_TAG] { - switch (str) { ->str : P_TAG -> : ^^^^^ - - case "auth": ->"auth" : "auth" -> : ^^^^^^ - - return { username: "test", password: "admin" }; ->{ username: "test", password: "admin" } : { username: string; password: string; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->username : string -> : ^^^^^^ ->"test" : "test" -> : ^^^^^^ ->password : string -> : ^^^^^^ ->"admin" : "admin" -> : ^^^^^^^ - - case "cart": ->"cart" : "cart" -> : ^^^^^^ - - return { items: [{ id: "123", quantity: 123 }] }; ->{ items: [{ id: "123", quantity: 123 }] } : { items: { id: string; quantity: number; }[]; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->items : { id: string; quantity: number; }[] -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->[{ id: "123", quantity: 123 }] : { id: string; quantity: number; }[] -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->{ id: "123", quantity: 123 } : { id: string; quantity: number; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->id : string -> : ^^^^^^ ->"123" : "123" -> : ^^^^^ ->quantity : number -> : ^^^^^^ ->123 : 123 -> : ^^^ - - default: - throw new Error("unhandled tag"); ->new Error("unhandled tag") : Error -> : ^^^^^ ->Error : ErrorConstructor -> : ^^^^^^^^^^^^^^^^ ->"unhandled tag" : "unhandled tag" -> : ^^^^^^^^^^^^^^^ - } -} - -// ok, exhaustive cases -function mockPayload3<P_TAG extends Payload["_tag"]>( ->mockPayload3 : <P_TAG extends Payload["_tag"]>(str: P_TAG) => PayloadContent[P_TAG] -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ - - str: P_TAG, ->str : P_TAG -> : ^^^^^ - -): PayloadContent[P_TAG] { - switch (str) { ->str : P_TAG -> : ^^^^^ - - case "auth": ->"auth" : "auth" -> : ^^^^^^ - - return { username: "test", password: "admin" }; ->{ username: "test", password: "admin" } : { username: string; password: string; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->username : string -> : ^^^^^^ ->"test" : "test" -> : ^^^^^^ ->password : string -> : ^^^^^^ ->"admin" : "admin" -> : ^^^^^^^ - - case "cart": ->"cart" : "cart" -> : ^^^^^^ - - return { items: [{ id: "123", quantity: 123 }] }; ->{ items: [{ id: "123", quantity: 123 }] } : { items: { id: string; quantity: number; }[]; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->items : { id: string; quantity: number; }[] -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->[{ id: "123", quantity: 123 }] : { id: string; quantity: number; }[] -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->{ id: "123", quantity: 123 } : { id: string; quantity: number; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->id : string -> : ^^^^^^ ->"123" : "123" -> : ^^^^^ ->quantity : number -> : ^^^^^^ ->123 : 123 -> : ^^^ - - case "person": ->"person" : "person" -> : ^^^^^^^^ - - return { name: "andrea", age: 27 }; ->{ name: "andrea", age: 27 } : { name: string; age: number; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->name : string -> : ^^^^^^ ->"andrea" : "andrea" -> : ^^^^^^^^ ->age : number -> : ^^^^^^ ->27 : 27 -> : ^^ - } -} - -// error, non-exhaustive cases -function mockPayload4<P_TAG extends Payload["_tag"]>( ->mockPayload4 : <P_TAG extends Payload["_tag"]>(str: P_TAG) => PayloadContent[P_TAG] -> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^ - - str: P_TAG, ->str : P_TAG -> : ^^^^^ - -): PayloadContent[P_TAG] { - switch (str) { ->str : P_TAG -> : ^^^^^ - - case "auth": ->"auth" : "auth" -> : ^^^^^^ - - return { username: "test", password: "admin" }; ->{ username: "test", password: "admin" } : { username: string; password: string; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->username : string -> : ^^^^^^ ->"test" : "test" -> : ^^^^^^ ->password : string -> : ^^^^^^ ->"admin" : "admin" -> : ^^^^^^^ - - case "cart": ->"cart" : "cart" -> : ^^^^^^ - - return { items: [{ id: "123", quantity: 123 }] }; ->{ items: [{ id: "123", quantity: 123 }] } : { items: { id: string; quantity: number; }[]; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->items : { id: string; quantity: number; }[] -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->[{ id: "123", quantity: 123 }] : { id: string; quantity: number; }[] -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->{ id: "123", quantity: 123 } : { id: string; quantity: number; } -> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ->id : string -> : ^^^^^^ ->"123" : "123" -> : ^^^^^ ->quantity : number -> : ^^^^^^ ->123 : 123 -> : ^^^ - } -} - diff --git a/tests/cases/compiler/conditionalReturnExpression.ts b/tests/cases/compiler/conditionalReturnExpression.ts new file mode 100644 index 0000000000000..8c1aefe8d5e33 --- /dev/null +++ b/tests/cases/compiler/conditionalReturnExpression.ts @@ -0,0 +1,24 @@ +// @noEmit: true +// @target: esnext + +function return1(x: boolean): 3 { + return (x ? (1) : 2); +} + +declare function getAny(): any; + +function return2(x: string): string { + return x.startsWith("a") ? getAny() : 1; +} + +function return3(x: string): string { + return x.startsWith("a") ? "a" : x; +} + +function return4(x: string): string { + return (x.startsWith("a") ? getAny() : 1) as string; +} + +const return5 = (x: string): string => x.startsWith("a") ? getAny() : 1; + +const return6 = (x: string): string => (x.startsWith("a") ? getAny() : 1) as string; \ No newline at end of file diff --git a/tests/cases/compiler/dependentReturnType1.ts b/tests/cases/compiler/dependentReturnType1.ts deleted file mode 100644 index 7527d3015bc3b..0000000000000 --- a/tests/cases/compiler/dependentReturnType1.ts +++ /dev/null @@ -1,519 +0,0 @@ -// @strict: true -// @noEmit: true -// @target: esnext - -interface A { - 1: number; - 2: string; -} - -function f1<T extends 1 | 2>(x: T): A[T] { - if (x === 1) { - return 0; // Ok - } - else { - return 1; // Error - } -} - -interface C { - 1: number; - 2: string; - 3: boolean; -} - -function f2<T extends 1 | 2 | 3>(x: T): C[T] { - if (x === 1) { - return 0; // Ok - } - else { - return ""; // Error, returned expression needs to have type string & boolean (= never) - } -} - -function f3<T extends 1 | 2 | 3>(x: T): T extends 1 ? number : T extends 2 ? string : T extends 3 ? boolean : never { - if (x === 1) { - return 0; // Ok - } - else { - return ""; // Error, returned expression needs to have type string & boolean (= never) - } -} - -interface One { - a: "a"; - b: "b"; - c: "c"; - d: "d"; -} - -interface Two { - a: "a"; - b: "b"; - e: "e"; - f: "f"; -} - -interface Three { - a: "a"; - c: "c"; - e: "e"; - g: "g"; -} - -interface Four { - a: "a"; - d: "d"; - f: "f"; - g: "g"; -} -// Badly written conditional return type, will not trigger narrowing -function f10<T extends 1 | 2 | 3 | 4>(x: T): T extends 1 ? One : T extends 2 ? Two : T extends 3 ? Three : Four { - if (x === 1 || x === 2) { - return { a: "a", b: "b", c: "c", d: "d", e: "e", f: "f" }; // Error - } - return { a: "a", b: "b", c: "c", d: "d", e: "e", f: "f", g: "g" }; // Error -} -// Well written conditional -function f101<T extends 1 | 2 | 3 | 4>(x: T): T extends 1 ? One : T extends 2 ? Two : T extends 3 ? Three : T extends 4 ? Four : never { - if (x === 1 || x === 2) { - return { a: "a", b: "b", c: "c", d: "d", e: "e", f: "f" }; // Ok - } - // Excess property becomes a problem with the change, - // because we now check assignability to a narrower type... - return { a: "a", b: "b", c: "c", d: "d", e: "e", f: "f", g: "g" }; // EPC Error -} - -// This will not work for several reasons: -// - first because the constraint of type parameter `Arg` is generic, -// so attempting to narrow the type of `arg` in the `if` would result in type `Arg & LeftIn`, -// which when substituted in the conditional return type, would not further resolve that conditional type -// - second because the `else` branch would never work because we don't narrow the type of `arg` to `Arg & RightIn` -function conditionalProducingIf<LeftIn, RightIn, LeftOut, RightOut, Arg extends LeftIn | RightIn>( - arg: Arg, - cond: (arg: LeftIn | RightIn) => arg is LeftIn, - produceLeftOut: (arg: LeftIn) => LeftOut, - produceRightOut: (arg: RightIn) => RightOut): - Arg extends LeftIn ? LeftOut : Arg extends RightIn ? RightOut : never -{ - if (cond(arg)) { - return produceLeftOut(arg); - } else { - return produceRightOut(arg as RightIn); - } -} - -interface Animal { - name: string; -} - -interface Dog extends Animal { - bark: () => string; -} - -// This would be unsafe to narrow. -declare function isDog(x: Animal): x is Dog; -declare function doggy(x: Dog): number; -function f12<T extends Animal>(x: T): T extends Dog ? number : string { - if (isDog(x)) { // `x` has type `T & Dog` here - return doggy(x); - } - return ""; // Error: Should not work because we can't express "not a Dog" in the type system -} - -// Cannot narrow `keyof` too eagerly or something like the below breaks -function f<Entry extends { [index: string]: number | boolean }, EntryId extends keyof Entry>(entry: EntryId): Entry[EntryId] { - const entries = {} as Entry; - return entries[entry]; -} - -// Works the same as before -declare function takeA(val: 'A'): void; -export function bounceAndTakeIfA<AB extends 'A' | 'B'>(value: AB): AB { - if (value === 'A') { - takeA(value); - takeAB(value); - return value; - } - - return value; - function takeAB(val: AB): void {} -} - -// Works the same as before -export function bbb<AB extends "a" | "b">(value: AB): "a" { - if (value === "a") { - return value; - } - return "a"; -} - -class Unnamed { - root!: { name: string }; - // Error: No narrowing because parameter is optional but `T` doesn't allow for undefined - name<T extends string>(name?: T): T extends string ? this : T extends undefined ? string : never { - if (typeof name === 'undefined') { - return this.root.name; - } - return this; - } - - // Good conditional - name2<T extends string | undefined>(name?: T): T extends string ? this : T extends undefined ? string : never { - if (typeof name === 'undefined') { - return this.root.name; // Ok - } - this.root.name = name; - return this; // Ok - } - - // Good conditional, wrong return expressions - name3<T extends string | undefined>(name?: T): T extends string ? this : T extends undefined ? string : never { - if (typeof name === 'undefined') { - return this; // Error - } - this.root.name = name; - return name; // Error - } -} - -// Conditional expressions -interface Aa { - 1: number; - 2: string; - 3: boolean; -} - -function trivialConditional<T extends 1 | 2 | 3>(x: T): Aa[T] { - if (x !== 1) { - return x === 2 ? "" : true; - } - else { - return 0; - } -} - -function conditional<T extends boolean>(x: T): - T extends true ? 1 : T extends false ? 2 : never { - return x ? 1 : 2; // Ok -} - -function contextualConditional<T extends "a" | "b">( - x: T -): T extends "a" ? "a" : T extends "b" ? number : never { - return x === "a" ? x : parseInt(x); // Ok -} - -function conditionalWithError<T extends "a" | "b">( - x: T -): T extends "a" ? number : T extends "b" ? string : never { - return x === "a" ? x : parseInt(x); // Error -} - -// Multiple indexed type reductions -interface BB { - "a": number; - [y: number]: string; -} - -interface AA<T extends keyof BB> { - "c": BB[T]; - "d": boolean, -} - -function reduction<T extends keyof BB, U extends "c" | "d">(x: T, y: U): AA<T>[U] { - if (y === "c" && x === "a") { - // AA<T>[U='c'] -> BB[T] - // BB[T='a'] -> number - return 0; // Ok - } - - return undefined as never; -} - -// Substitution types are not narrowed -function subsCond<T extends 1 | 2 | 3>( - x: T, -): T extends 1 | 2 - ? T extends 1 - ? string - : T extends 2 - ? boolean - : never - : T extends 3 - ? number - : never { - if (x === 1) { - return ""; - } else if (x == 2) { - return true; - } - return 3; -} - - -// Unsafe: check types overlap -declare function q(x: object): x is { b: number }; -function foo<T extends { a: string } | { b: number }>( - x: T, -): T extends { a: string } ? number : T extends { b: number } ? string : never { - if (q(x)) { - x.b; - return ""; - } - x.a; - return 1; -} - -let y = { a: "", b: 1 } -const r = foo<{ a: string }>(y); // type says number but actually string - -type HelperCond<T, A, R1, B, R2> = T extends A ? R1 : T extends B ? R2 : never; - -// We don't narrow the return type because the conditionals are not distributive -function foo2<U extends string | number, V extends boolean>(x: U, y: V): - HelperCond<{ x: U, y: V }, - { x: string, y: true }, 1, - { x: number, y: false }, 2> { - if (typeof x === "string" && y === true) { - return 1; // Error - } - if (typeof x === "number" && y === false) { - return 2; // Error - } - return 0; // Error -} - -// From https://github.com/microsoft/TypeScript/issues/24929#issue-332087943 -declare function isString(s: unknown): s is string; -// capitalize a string or each element of an array of strings -function capitalize<T extends string | string[]>( - input: T -): T extends string[] ? string[] : T extends string ? string : never { - if (isString(input)) { - return input[0].toUpperCase() + input.slice(1); // Ok - } else { - return input.map(elt => capitalize(elt)); // Ok - } -} - -function badCapitalize<T extends string | string[]>( - input: T -): T extends string[] ? string[] : T extends string ? string : never { - if (isString(input)) { - return input[0].toUpperCase() + input.slice(1); // Ok - } else { - return input[0].toUpperCase() + input.slice(1); // Bad, error - } -} - -// No narrowing because conditional's extends type is different from type parameter constraint types -function voidRet<T extends { a: string } | undefined>( - x: T -): T extends {} ? void : T extends undefined ? number : never { - if (x) { - return; - } - return 1; -} - -// Multiple type parameters at once -function woo<T extends string | number, U extends string | number>( - x: T, - y: U, -): T extends string - ? U extends string - ? 1 - : U extends number - ? 2 - : never - : T extends number - ? U extends number - ? 3 - : U extends string - ? 4 - : never - : never { - if (typeof x === "number" && typeof y === "string") { - return 1; // Good error - } - return undefined as any; -} - -function ttt<T extends string | number, U extends string | number>( - x: T, - y: U, -): T extends string - ? U extends string - ? 1 - : U extends number - ? 2 - : never - : T extends number - ? U extends number - ? 3 - : U extends string - ? 4 - : never - : never { - if (typeof x === "number" && typeof y === "string") { - return 4; // Ok - } - - return undefined as any; -} - -// Shadowing of the narrowed reference -function shadowing<T extends 1 | 2>(x: T): T extends 1 ? number : T extends 2 ? string : never { - if (true) { - let x: number = Math.random() ? 1 : 2; - if (x === 1) { - return 1; // Error - } - return ""; // Error - } -} - -function noShadowing<T extends 1 | 2>(x: T): T extends 1 ? number : T extends 2 ? string : never { - if (true) { - if (x === 1) { - return 1; // Ok - } - return ""; // Ok - } -} - -// If the narrowing reference is out of scope, we simply won't narrow its type -declare let someX: boolean; -function scope2<T extends boolean>(a: T): T extends true ? 1 : T extends false ? 2 : never { - if ((true)) { - const someX = a; - if (someX) { // We narrow `someX` and the return type here - return 1; - } - } - if (!someX) { // This is a different `someX`, so we don't narrow here - return 2; - } - - return undefined as any; -} - -function moreShadowing<T extends 1 | 2>(x: T): T extends 1 ? number : T extends 2 ? string : never { - if (x === 2) { - let x: number = Math.random() ? 1 : 2; - if (x === 1) { - return 1; // Error - } - return ""; // Ok - } - return 0; // Ok -} - -// This would be unsafe to narrow due to `infer` type. -function withInfer<T extends [string] | number>(x: T): T extends [infer R] ? R : T extends number ? boolean : never { - if (typeof x === "number") { - return true; - } - return ""; -} - -const withInferResult = withInfer(["a"] as const); // The type says it returns `"a"`, but the function actually returns `""`. - -// Ok -async function abool<T extends true | false>(x: T): Promise<T extends true ? 1 : T extends false ? 2 : never> { - if (x) { - return 1; - } - return 2; -} - -// Ok -function* bbool<T extends true | false>(x: T): Generator<number, T extends true ? 1 : T extends false ? 2 : never, unknown> { - yield 3; - if (x) { - return 1; - } - return 2; -} - -// We don't do the same type of narrowing for `yield` statements -function* cbool<T extends true | false>(x: T): Generator<T extends true ? 1 : T extends false ? 2 : never, number, unknown> { - if (x) { - yield 1; - } - yield 2; - return 0; -} - -// From #33912 -abstract class Operation<T, R> { - abstract perform(t: T): R; -} - -type ConditionalReturnType<T, R, EOp extends Operation<T, R> | undefined> = - EOp extends Operation<T, R> ? R : EOp extends undefined ? T | R : never; - - -class ConditionalOperation< - T, - R, - EOp extends Operation<T, R> | undefined, -> extends Operation<T, ConditionalReturnType<T, R, EOp>> { - constructor( - private predicate: (value: T) => boolean, - private thenOp: Operation<T, R>, - private elseOp?: EOp, - ) { - super(); - } - - // We won't try to narrow the return type because `T` is declared on the class and we don't analyze this case. - perform(t: T): ConditionalReturnType<T, R, EOp> { - if (this.predicate(t)) { - return this.thenOp.perform(t); // Bad: this is assignable to all of the branches of the conditional, but we still can't return it - } else if (typeof this.elseOp !== "undefined") { - return this.elseOp.perform(t); // Would be ok - } else { - return t; // Would be ok - } - } -} - -// Like the version above, we will not attempt to narrow because there's more than one reference to `T`, -// because `T` shows up in the type of `predicate`. -function perform<T, R, EOp extends Operation<T, R> | undefined>( - t: T, - predicate: (value: T) => boolean, - thenOp: Operation<T, R>, - elseOp?: EOp, - ): ConditionalReturnType<T, R, EOp> { - if (predicate(t)) { - return thenOp.perform(t); // Bad: this is assignable to all of the branches of the conditional, but we still can't return it - } else if (elseOp !== undefined) { - return elseOp.perform(t); // Would be ok - } else { - return t; // Would be ok - } -} - -// Return conditional expressions with parentheses -function returnStuff1<T extends boolean>(x: T ): T extends true ? 1 : T extends false ? 2 : never { - return (x ? (1) : 2); -} - -function returnStuff2<T extends 1 | 2 | "a">(x: T ): - T extends 1 ? "one" : T extends 2 ? "two" : T extends "a" ? 0 : never { - return (typeof x === "string" ? 0 : (x === 1 ? ("one") : "two")); -} - -// If the conditional type's input is `never`, then it resolves to `never`: -function neverOk<T extends boolean>(x: T): T extends true ? 1 : T extends false ? 2 : never { - if (x === true) { - return 1; - } - if (x === false) { - return 2; - } - return 1; -} \ No newline at end of file diff --git a/tests/cases/compiler/dependentReturnType2.ts b/tests/cases/compiler/dependentReturnType2.ts deleted file mode 100644 index 0f14e3f7faa87..0000000000000 --- a/tests/cases/compiler/dependentReturnType2.ts +++ /dev/null @@ -1,307 +0,0 @@ -// @strict: true -// @noEmit: true -// @target: esnext -// @checkJs: true -// @filename: file.js - -// Adapted from ts-error-deltas repos - -/** - * @template T - * @template A - * @template R1 - * @template B - * @template R2 - * @typedef {T extends A ? R1 : T extends B ? R2 : never} HelperCond - */ - -/** - * @typedef IMessage - * @property {string} [html] - * @property {Object[]} [tokens] - */ - -class NewKatex { - /** - * @param {string} s - * @returns {string} - */ - render(s) { - return ""; - } - - /** - * @template {string | IMessage} T - * @param {T} message - * @returns {T extends string ? string : T extends IMessage ? IMessage : never} - */ - renderMessage(message) { - if (typeof message === 'string') { - return this.render(message); // Ok - } - - if (!message.html?.trim()) { - return message; // Ok - } - - if (!message.tokens) { - message.tokens = []; - } - - message.html = this.render(message.html); - return message; // Ok - } -} - -/** - * @template {true | false} T - * @param {{ dollarSyntax: boolean; parenthesisSyntax: boolean; }} options - * @param {T} _isMessage - * @returns {T extends true ? (message: IMessage) => IMessage : T extends false ? (message: string) => string : never} - */ -function createKatexMessageRendering(options, _isMessage) { - const instance = new NewKatex(); - if (_isMessage) { - return (/** @type {IMessage} */ message) => instance.renderMessage(message); // Ok - } - return (/** @type {string} */ message) => instance.renderMessage(message); // Ok -} - -// File: Rocket.Chat/apps/meteor/app/settings/lib/settings.ts - -/** - * @typedef {Record<any, any>} MyObj - */ - - -/** - * @typedef {MyObj} SettingValue - */ - -/** - * @template {SettingValue} T - * @typedef {Object} SettingComposedValue - * @property {string} key - * @property {SettingValue} value - */ - -/** - * @callback SettingCallback - * @param {string} key - * @param {SettingValue} value - * @param {boolean} [initialLoad] - * @returns {void} - */ - -/** @type {{ settings: { [s: string]: any } }} */ -const Meteor = /** @type {any} */ (undefined); -/** @type {{ isRegExp(x: unknown): x is RegExp; }} */ -const _ = /** @type {any} */ (undefined); - -/** - * @param {RegExp} x - * @returns {void} - */ -function takesRegExp(x) { - return /** @type {any} */ undefined; -} -/** - * @param {string} x - * @returns {void} - */ -function takesString(x) { - return /** @type {any} */ undefined; -} - -/** - * @class NewSettingsBase - */ -class NewSettingsBase { - /** - * @template {SettingCallback | undefined} C - * @template {string | RegExp} I - * @template {SettingValue} T - * @param {I} _id - * @param {C} [callback] - * @returns {HelperCond<C, SettingCallback, void, undefined, HelperCond<I, string, T | undefined, RegExp, SettingComposedValue<T>[]>>} - */ - newGet(_id, callback) { - if (callback !== undefined) { - if (!Meteor.settings) { - return; // Ok - } - if (_id === '*') { - return Object.keys(Meteor.settings).forEach((key) => { - const value = Meteor.settings[key]; - callback(key, value); - }); - } - if (_.isRegExp(_id) && Meteor.settings) { - return Object.keys(Meteor.settings).forEach((key) => { - if (!_id.test(key)) { - return; - } - const value = Meteor.settings[key]; - callback(key, value); - }); - } - - if (typeof _id === 'string') { - const value = Meteor.settings[_id]; - if (value != null) { - callback(_id, Meteor.settings[_id]); - } - return; // Ok - } - - return; // Ok, needed for exhaustiveness check - } - - if (!Meteor.settings) { - return undefined; // Error - } - - if (_.isRegExp(_id)) { - return Object.keys(Meteor.settings).reduce((/** @type {SettingComposedValue<T>[]} */ items, key) => { - const value = Meteor.settings[key]; - if (_id.test(key)) { - items.push({ key, value }); - } - return items; - }, []); // Ok - } - - return Meteor.settings?.[_id]; // Error - } -} - -// File: Rocket.Chat/apps/meteor/app/ui-utils/client/lib/messageBox.ts - -/** - * @typedef {MyObj} MessageBoxAction - */ - -/** - * @template {string | undefined} T - * @param {T} group - * @returns {HelperCond<T, string, MessageBoxAction[], undefined, Record<string, MessageBoxAction[]>>} - */ -function getWithBug(group) { - if (!group) { - return /** @type {Record<string, MessageBoxAction[]>} */({}); // Error - } - return /** @type {MessageBoxAction[]} */([]); // Ok -} - -/** - * @template {string | undefined} T - * @param {T} group - * @returns {HelperCond<T, string, MessageBoxAction[], undefined, Record<string, MessageBoxAction[]>>} - */ -function getWithoutBug(group) { - if (group === undefined) { - return /** @type {Record<string, MessageBoxAction[]>} */({}); // Ok - } - return /** @type {MessageBoxAction[]} */([]); // Ok -} - -// File: Rocket.Chat/apps/meteor/ee/server/lib/engagementDashboard/date.ts - -/** - * @param {string} x - * @returns {Date} - */ -function mapDateForAPI(x) { - return /** @type {any} */ (undefined); -} - -/** - * @template {string | undefined} T - * @param {string} start - * @param {T} [end] - * @returns {HelperCond<T, string, { start: Date, end: Date }, undefined, { start: Date, end: undefined }>} - */ -function transformDatesForAPI(start, end) { - return end !== undefined ? - { - start: mapDateForAPI(start), - end: mapDateForAPI(end), - } : - { - start: mapDateForAPI(start), - end: undefined - }; -} - -// File: Rocket.Chat/packages/agenda/src/Agenda.ts - -/** - * @typedef {MyObj} RepeatOptions - */ - -/** - * @typedef {MyObj} Job - */ - -/** - * @typedef {Object} IJob - * @property {MyObj} data - */ -class NewAgenda { - /** - * @param {string | number} interval - * @param {string} name - * @param {IJob['data']} data - * @param {RepeatOptions} options - * @returns {Promise<Job>} - */ - async _createIntervalJob(interval, name, data, options) { - return /** @type {any} */ (undefined); - } - - /** - * @param {string | number} interval - * @param {string[]} names - * @param {IJob['data']} data - * @param {RepeatOptions} options - * @returns {Promise<Job[]> | undefined} - */ - _createIntervalJobs(interval, names, data, options) { - return undefined; - } - - /** - * @template {string | string[]} T - * @param {string | number} interval - * @param {T} name - * @param {IJob['data']} data - * @param {RepeatOptions} options - * @returns {Promise<HelperCond<T, string, Job, string[], Job[] | undefined>>} - */ - async newEvery(interval, name, data, options) { - if (typeof name === 'string') { - return this._createIntervalJob(interval, name, data, options); // Ok - } - - if (Array.isArray(name)) { - return this._createIntervalJobs(interval, name, data, options); // Ok - } - - throw new Error('Unexpected error: Invalid job name(s)'); - } -} - -// File: angular/packages/common/src/pipes/case_conversion_pipes.ts - -/** - * @template {string | null | undefined} T - * @param {T} value - * @returns {HelperCond<T, string, string, null | undefined, null>} - */ -function transform1(value) { - if (value == null) return null; // Ok - if (typeof value !== 'string') { - throw new Error(); - } - return value.toLowerCase(); // Ok -} diff --git a/tests/cases/compiler/dependentReturnType3.ts b/tests/cases/compiler/dependentReturnType3.ts deleted file mode 100644 index df60c0677fd5d..0000000000000 --- a/tests/cases/compiler/dependentReturnType3.ts +++ /dev/null @@ -1,216 +0,0 @@ -// @strict: true -// @noEmit: true -// @target: ES6 - -// Adapted from ts-error-deltas repos - -type HelperCond<T, A, R1, B, R2> = - T extends A - ? R1 - : T extends B - ? R2 - : never; - - -// File: Rocket.Chat/apps/meteor/app/katex/client/index.ts -interface IMessage { - html?: string; - tokens?: {}[]; -} - -class NewKatex { - render(s: string): string { - return ""; - } - - renderMessage<T extends string | IMessage>(message: T): - T extends string - ? string - : T extends IMessage - ? IMessage - : never { - if (typeof message === 'string') { - return this.render(message); // Ok - } - - if (!message.html?.trim()) { - return message; // Ok - } - - if (!message.tokens) { - message.tokens = []; - } - - message.html = this.render(message.html); - return message; // Ok - } -} - -export function createKatexMessageRendering<T extends true | false>( - options: { - dollarSyntax: boolean; - parenthesisSyntax: boolean; - }, - _isMessage: T, -): T extends true - ? (message: IMessage) => IMessage - : T extends false - ? (message: string) => string - : never { - const instance = new NewKatex(); - if (_isMessage) { - return (message: IMessage): IMessage => instance.renderMessage(message); // Ok - } - return (message: string): string => instance.renderMessage(message); // Ok -} - -// File: Rocket.Chat/apps/meteor/app/settings/lib/settings.ts -type SettingComposedValue<T extends SettingValue = SettingValue> = { key: string; value: T }; -type SettingCallback = (key: string, value: SettingValue, initialLoad?: boolean) => void; - -type SettingValue = object; -declare const Meteor: { settings: { [s: string]: any } }; -declare const _: { isRegExp(x: unknown): x is RegExp; }; -declare function takesRegExp(x: RegExp): void; -declare function takesString(x: string): void; - -class NewSettingsBase { - public newGet<C extends SettingCallback | undefined, I extends string | RegExp, T extends SettingValue = SettingValue>( - _id: I, - callback?: C, - ): HelperCond<C, - SettingCallback, void, - undefined, HelperCond<I, - string, T | undefined, - RegExp, SettingComposedValue<T>[]>> { - if (callback !== undefined) { - if (!Meteor.settings) { - return; // Ok - } - if (_id === '*') { - return Object.keys(Meteor.settings).forEach((key) => { // Ok - const value = Meteor.settings[key]; - callback(key, value); - }); - } - if (_.isRegExp(_id) && Meteor.settings) { - return Object.keys(Meteor.settings).forEach((key) => { // Ok - if (!_id.test(key)) { - return; - } - const value = Meteor.settings[key]; - callback(key, value); - }); - } - - if (typeof _id === 'string') { - const value = Meteor.settings[_id]; - if (value != null) { - callback(_id, Meteor.settings[_id]); - } - return; // Ok - } - - return; // Ok, needed for exhaustiveness check - } - - if (!Meteor.settings) { // Wrong: we don't know that _id is string here, cannot return undefined - return undefined; // Error - } - - if (_.isRegExp(_id)) { - return Object.keys(Meteor.settings).reduce((items: SettingComposedValue<T>[], key) => { - const value = Meteor.settings[key]; - if (_id.test(key)) { - items.push({ - key, - value, - }); - } - return items; - }, []); // Ok - } - - return Meteor.settings?.[_id]; // Error - // The indexing currently doesn't work because it doesn't use the narrowed type of `_id`. - } -} - -// File: Rocket.Chat/apps/meteor/app/ui-utils/client/lib/messageBox.ts -type MessageBoxAction = object; - -function getWithBug<T extends string | undefined>(group: T): -HelperCond<T, string, MessageBoxAction[], undefined, Record<string, MessageBoxAction[]>> { - if (!group) { - return {} as Record<string, MessageBoxAction[]>; // Error, could fall into this branch when group is empty string - } - - return [] as MessageBoxAction[]; // Ok -} - -function getWithoutBug<T extends string | undefined>(group: T): -HelperCond<T, string, MessageBoxAction[], undefined, Record<string, MessageBoxAction[]>> { - if (group === undefined) { - return {} as Record<string, MessageBoxAction[]>; // Ok - } - - return [] as MessageBoxAction[]; // Ok -} - -// File: Rocket.Chat/apps/meteor/ee/server/lib/engagementDashboard/date.ts -declare function mapDateForAPI(x: string): Date; -export function transformDatesForAPI<T extends string | undefined>( - start: string, - end?: T -): HelperCond<T, string, { start: Date, end: Date }, undefined, { start: Date, end: undefined }> { - return end !== undefined ? // Ok - { - start: mapDateForAPI(start), - end: mapDateForAPI(end), - } : - { - start: mapDateForAPI(start), - end: undefined - }; -} - -// File: Rocket.Chat/packages/agenda/src/Agenda.ts -type RepeatOptions = object; -type Job = object; -type IJob = { data: object }; -class NewAgenda { - public async _createIntervalJob(interval: string | number, name: string, data: IJob['data'], options: RepeatOptions): Promise<Job> { return undefined as any; } - private _createIntervalJobs( - interval: string | number, - names: string[], - data: IJob['data'], - options: RepeatOptions, - ): Promise<Job[]> | undefined { return undefined as any; } - - public async newEvery<T extends string | string[]>( - interval: string | number, - name: T, - data: IJob['data'], - options: RepeatOptions): Promise<HelperCond<T, string, Job, string[], Job[] | undefined>> { - if (typeof name === 'string') { - return this._createIntervalJob(interval, name, data, options); // Ok - } - - if (Array.isArray(name)) { - return this._createIntervalJobs(interval, name, data, options); // Ok - // Possible bug in original: createIntervalJobs can return undefined, but the original overload did not acount for that. - } - - throw new Error('Unexpected error: Invalid job name(s)'); - } -} - -// File: angular/packages/common/src/pipes/case_conversion_pipes.ts - -function transform1<T extends string | null | undefined>(value: T): HelperCond<T, string, string, null | undefined, null> { - if (value == null) return null; // Ok - if (typeof value !== 'string') { - throw new Error(); - } - return value.toLowerCase(); // Ok -} \ No newline at end of file diff --git a/tests/cases/compiler/dependentReturnType4.ts b/tests/cases/compiler/dependentReturnType4.ts deleted file mode 100644 index 166b8497fa3eb..0000000000000 --- a/tests/cases/compiler/dependentReturnType4.ts +++ /dev/null @@ -1,36 +0,0 @@ -// @strict: true -// @noEmit: true -// @target: ES2022 -// @exactOptionalPropertyTypes: true - -declare const rand: { a?: never }; -type Missing = typeof rand.a; - -// Detection of valid optional parameter references - -// Ok, will narrow return type -function bar1<T extends string | Missing>(x?: T): - T extends Missing ? 0 : T extends string ? 1 : never { - if (x === undefined) { - return 0; - } - return 1; -} - -// Ok, will narrow return type -function bar2<T extends string | undefined>(x?: T): - T extends undefined ? 0 : T extends string ? 1 : never { - if (x === undefined) { - return 0; - } - return 1; -} - -// Not ok, will not narrow return type -function bar3<T extends string>(x?: T): - T extends undefined ? 0 : T extends string ? 1 : never { - if (x === undefined) { - return 0; - } - return 1; -} \ No newline at end of file diff --git a/tests/cases/compiler/dependentReturnType5.ts b/tests/cases/compiler/dependentReturnType5.ts deleted file mode 100644 index 137474217ecb7..0000000000000 --- a/tests/cases/compiler/dependentReturnType5.ts +++ /dev/null @@ -1,99 +0,0 @@ -// @strict: true -// @noEmit: true - -// Indexed access return type -interface A1 { - "prop": true; - [s: string]: boolean; -} - -// This was already allowed but is unsound. -function foo1<T extends string>(x: T): A1[T] { - return false; -} -const rfoo1 = foo1("prop"); // Type says true, but actually returns false. - -interface A2 { - "prop": true; - [n: number]: string; -} - -// We could soundly allow that, because `"prop"` and `[n: number]` are disjoint types. -function foo2<T extends "prop" | number>(x: T): A2[T] { - if (x === "prop") { - return true; - } - return "some string"; -} -const rfoo2 = foo2("prop"); -const rfoo22 = foo2(34); -const rfoo222 = foo2(Math.random() ? "prop" : 34); - -interface A3 { - [s: string]: boolean; -} - -// No need for return type narrowing. -function foo3<T extends string>(x: T): A3[T] { - if (Math.random()) return true; - return false; -} - -interface Comp { - foo: 2; - [n: number]: 3; - [s: string]: 2 | 3 | 4; -} - -function indexedComp<T extends number | string>(x: T): Comp[T] { - if (x === "foo") { - if (Math.random()) { - return 3; // Error - } - return 2; // Ok - } - if (typeof x === "number") { - if (Math.random()) { - return 2; // Error - } - return 3; // Ok - } - return 4; // Ok -} - -function indexedComp2<T extends number | string>(x: T): Comp[T] { - if (Math.random()) { - return 3; // Bad, unsound - } - return 2; // Error -} - - -// Most common case supported: -interface F { - "t": number, - "f": boolean, -} - -// Ok -function depLikeFun<T extends "t" | "f">(str: T): F[T] { - if (str === "t") { - return 1; - } else { - return true; - } -} - -depLikeFun("t"); // has type number -depLikeFun("f"); // has type boolean - -type IndirectF<T extends keyof F> = F[T]; - -// Ok -function depLikeFun2<T extends "t" | "f">(str: T): IndirectF<T> { - if (str === "t") { - return 1; - } else { - return true; - } -} \ No newline at end of file diff --git a/tests/cases/compiler/dependentReturnType6.ts b/tests/cases/compiler/dependentReturnType6.ts deleted file mode 100644 index 4a319fa7f401a..0000000000000 --- a/tests/cases/compiler/dependentReturnType6.ts +++ /dev/null @@ -1,137 +0,0 @@ -// @strict: true -// @noEmit: true -// @target: esnext - -// Tests for when return type narrowing can and cannot happen - -// @filename: file.ts -// Type parameter in outer scope -function outer<T extends boolean>(x: T): number { - return inner(); - - function inner(): T extends true ? 1 : T extends false ? 2 : never { - return x ? 1 : 2; - } -} - -// Overloads -function fun6<T extends boolean>(x: T, y: string): T extends true ? string : T extends false ? 2 : never; -function fun6<T extends boolean>(x: T, y: undefined): T extends true ? 1 : T extends false ? 2 : never; -function fun6(x: boolean): 1 | 2 | string; -function fun6<T extends boolean>(x: T, y?: string): T extends true ? 1 | string : T extends false ? 2 : never { - return x ? y !== undefined ? y : 1 : 2; -} - -// Indexed access with conditional inside - -// DOESN'T NARROW the nested conditional type of wrong shape -interface SomeInterfaceBad<T> { - prop1: T extends 1 ? true : T extends 2 ? false : never; - prop2: T extends true ? 1 : T extends false ? 2 : never; -} - -function fun4bad<T, U extends keyof SomeInterfaceBad<unknown>>(x: T, y: U): SomeInterfaceBad<T>[U] { - if (y === "prop1") { - return x === 1 ? true : false; - } - return x ? 1 : 2; -} - -// Narrows nested conditional type of right shape -interface SomeInterfaceGood<T> { - prop1: T extends true ? 2 : T extends false ? 1 : never; - prop2: T extends true ? 1 : T extends false ? 2 : never; -} - -function fun4good<T extends boolean, U extends keyof SomeInterfaceGood<unknown>>(x: T, y: U): SomeInterfaceGood<T>[U] { - if (y === "prop1") { - return x ? 2 : 1; - } - return x ? 1 : 2; -} - -// Indexed access with indexed access inside - OK, narrows -interface BB { - "a": number; - "b": string; -} - -interface AA<T extends keyof BB> { - "c": BB[T]; - "d": boolean, -} - -function reduction<T extends keyof BB, U extends keyof AA<any>>(x: T, y: U): AA<T>[U] { - if (x === "a" && y === "c") { - return 0; // Ok - } - - return undefined as never; -} - -// Conditional with indexed access inside - OK, narrows -function fun5<T extends 1 | 2, U extends keyof BB>(x: T, y: U): T extends 1 ? BB[U] : T extends 2 ? boolean : never { - if (x === 1) { - if (y === "a") { - return 0; - } - return ""; - } - return true; -} - -// `this` type parameter - Doesn't narrow -abstract class SomeClass { - fun3(this: Sub1 | Sub2): this extends Sub1 ? 1 : this extends Sub2 ? 2 : never { - if (this instanceof Sub1) { - return 1; - } - return 2; - } -} -class Sub1 extends SomeClass { - #sub1!: symbol; -}; -class Sub2 extends SomeClass { - #sub2!: symbol; -}; - -// Detection of type parameter reference in presence of typeof -function fun2<T extends boolean>(x: T, y: typeof x): T extends true ? 1 : T extends false ? 2 : never { - return x ? 1 : 2; -} - -// Contextually-typed lambdas -const fun1: <T extends boolean>(x: T) => T extends true ? 1 : T extends false ? 2 : never = (x) => x ? 1 : 2; - - -// Circular conditionals -type SomeCond<T> = T extends true ? 1 : T extends false ? SomeCond<T> : never; - -function f7<T extends boolean>(x: T): SomeCond<T> { - if (x) { - return 1; - } - return 2; -} - -// Composite instantiation of conditional type -type OtherCond<T> = T extends 1 ? "one" : T extends 2 ? "two" : T extends 3 ? "three" : T extends 4 ? "four" : never; - -function f8<U extends 1 | 2, V extends 3 | 4>(x: U, y: V): OtherCond<U | V> { - if (x === 1 && y === 3) { - return "one"; - } -} - -// Conditionals with `infer` - will not narrow, it is not safe to infer from the narrowed type into an `infer` type parameter -function f9<T extends "a"[] | "b"[] | number>(x: T): T extends Array<infer P> ? P : T extends number ? undefined : never { - if (Array.isArray(x)) { - // If we allowed narrowing of the conditional return type, when resolving the conditional `T & ("a"[] | "b"[]) extends Array<infer P> ? P : ...`, - // we could infer `"a" | "b"` for `P`, and allow "a" to be returned. However, when calling `f10`, `T` could be instantiated with `"b"[]`, and the return type would be `"b"`, - // so allowing an `"a"` return would be unsound. - return "a"; - } - return undefined; -} - diff --git a/tests/cases/compiler/dependentReturnType8.ts b/tests/cases/compiler/dependentReturnType8.ts deleted file mode 100644 index 169d5f540c2b6..0000000000000 --- a/tests/cases/compiler/dependentReturnType8.ts +++ /dev/null @@ -1,13 +0,0 @@ -// @strict: true -// @noEmit: true - - -export {}; - -declare const record: Record<string, string[]>; -declare const array: string[]; - -// Arrow function with expression body -const getObject = - <T extends string | undefined>(group: T): T extends string ? string[] : T extends undefined ? Record<string, string[]> : never => - group === undefined ? record : array; \ No newline at end of file diff --git a/tests/cases/compiler/dependentReturnType9.ts b/tests/cases/compiler/dependentReturnType9.ts deleted file mode 100644 index 65437a8aea1c8..0000000000000 --- a/tests/cases/compiler/dependentReturnType9.ts +++ /dev/null @@ -1,67 +0,0 @@ -// @strict: true -// @noEmit: true - -type Payload = - | { _tag: "auth"; username: string; password: string } - | { _tag: "cart"; items: Array<{ id: string; quantity: number }> } - | { _tag: "person"; name: string; age: number }; - -type PayloadContent = { - [P in Payload as P["_tag"]]: Omit<P, "_tag">; -}; - -// ok, exhaustive cases and default case with throw -function mockPayload<P_TAG extends Payload["_tag"]>( - str: P_TAG, -): PayloadContent[P_TAG] { - switch (str) { - case "auth": - return { username: "test", password: "admin" }; - case "cart": - return { items: [{ id: "123", quantity: 123 }] }; - case "person": - return { name: "andrea", age: 27 }; - default: - throw new Error("unknown tag"); - } -} - -// ok, non-exhaustive cases but default case with throw -function mockPayload2<P_TAG extends Payload["_tag"]>( - str: P_TAG, -): PayloadContent[P_TAG] { - switch (str) { - case "auth": - return { username: "test", password: "admin" }; - case "cart": - return { items: [{ id: "123", quantity: 123 }] }; - default: - throw new Error("unhandled tag"); - } -} - -// ok, exhaustive cases -function mockPayload3<P_TAG extends Payload["_tag"]>( - str: P_TAG, -): PayloadContent[P_TAG] { - switch (str) { - case "auth": - return { username: "test", password: "admin" }; - case "cart": - return { items: [{ id: "123", quantity: 123 }] }; - case "person": - return { name: "andrea", age: 27 }; - } -} - -// error, non-exhaustive cases -function mockPayload4<P_TAG extends Payload["_tag"]>( - str: P_TAG, -): PayloadContent[P_TAG] { - switch (str) { - case "auth": - return { username: "test", password: "admin" }; - case "cart": - return { items: [{ id: "123", quantity: 123 }] }; - } -} diff --git a/tests/cases/fourslash/returnTypeNarrowingAfterCachingTypes.ts b/tests/cases/fourslash/returnTypeNarrowingAfterCachingTypes.ts deleted file mode 100644 index fad2f1452fd11..0000000000000 --- a/tests/cases/fourslash/returnTypeNarrowingAfterCachingTypes.ts +++ /dev/null @@ -1,12 +0,0 @@ -/// <reference path="fourslash.ts" /> - -// @strict: true -//// function h<T extends boolean>(x: T): T extends true ? 1 : T extends false ? 2 : never { -//// if (x) { -//// return 1; -//// } -//// return 2; -//// } - -verify.encodedSemanticClassificationsLength("2020", 21); -verify.noErrors(); \ No newline at end of file