mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-06 02:33:53 -06:00
Propagate 'undefined' instead of the optional type marker at an optional chain boundary (#34588)
* Propagate 'undefined' instead of the optional type marker at an optional chain boundary * Update src/compiler/types.ts Co-Authored-By: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com>
This commit is contained in:
parent
ec367feb58
commit
ba5e86f140
@ -1556,10 +1556,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function isOutermostOptionalChain(node: OptionalChain) {
|
||||
return !isOptionalChain(node.parent) || isOptionalChainRoot(node.parent) || node !== node.parent.expression;
|
||||
}
|
||||
|
||||
function bindOptionalExpression(node: Expression, trueTarget: FlowLabel, falseTarget: FlowLabel) {
|
||||
doWithConditionalBranches(bind, node, trueTarget, falseTarget);
|
||||
if (!isOptionalChain(node) || isOutermostOptionalChain(node)) {
|
||||
|
||||
@ -8691,14 +8691,23 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
function getOptionalCallSignature(signature: Signature) {
|
||||
return signatureIsOptionalCall(signature) ? signature :
|
||||
(signature.optionalCallSignatureCache || (signature.optionalCallSignatureCache = createOptionalCallSignature(signature)));
|
||||
function getOptionalCallSignature(signature: Signature, callChainFlags: SignatureFlags): Signature {
|
||||
if ((signature.flags & SignatureFlags.CallChainFlags) === callChainFlags) {
|
||||
return signature;
|
||||
}
|
||||
if (!signature.optionalCallSignatureCache) {
|
||||
signature.optionalCallSignatureCache = {};
|
||||
}
|
||||
const key = callChainFlags === SignatureFlags.IsInnerCallChain ? "inner" : "outer";
|
||||
return signature.optionalCallSignatureCache[key]
|
||||
|| (signature.optionalCallSignatureCache[key] = createOptionalCallSignature(signature, callChainFlags));
|
||||
}
|
||||
|
||||
function createOptionalCallSignature(signature: Signature) {
|
||||
function createOptionalCallSignature(signature: Signature, callChainFlags: SignatureFlags) {
|
||||
Debug.assert(callChainFlags === SignatureFlags.IsInnerCallChain || callChainFlags === SignatureFlags.IsOuterCallChain,
|
||||
"An optional call signature can either be for an inner call chain or an outer call chain, but not both.");
|
||||
const result = cloneSignature(signature);
|
||||
result.flags |= SignatureFlags.IsOptionalCall;
|
||||
result.flags |= callChainFlags;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -10313,9 +10322,12 @@ namespace ts {
|
||||
signature.unionSignatures ? getUnionType(map(signature.unionSignatures, getReturnTypeOfSignature), UnionReduction.Subtype) :
|
||||
getReturnTypeFromAnnotation(signature.declaration!) ||
|
||||
(nodeIsMissing((<FunctionLikeDeclaration>signature.declaration).body) ? anyType : getReturnTypeFromBody(<FunctionLikeDeclaration>signature.declaration));
|
||||
if (signatureIsOptionalCall(signature)) {
|
||||
if (signature.flags & SignatureFlags.IsInnerCallChain) {
|
||||
type = addOptionalTypeMarker(type);
|
||||
}
|
||||
else if (signature.flags & SignatureFlags.IsOuterCallChain) {
|
||||
type = getOptionalType(type);
|
||||
}
|
||||
if (!popTypeResolution()) {
|
||||
if (signature.declaration) {
|
||||
const typeNode = getEffectiveReturnTypeNode(signature.declaration);
|
||||
@ -16767,8 +16779,8 @@ namespace ts {
|
||||
return strictNullChecks ? filterType(type, isNotOptionalTypeMarker) : type;
|
||||
}
|
||||
|
||||
function propagateOptionalTypeMarker(type: Type, wasOptional: boolean) {
|
||||
return wasOptional ? addOptionalTypeMarker(type) : type;
|
||||
function propagateOptionalTypeMarker(type: Type, node: OptionalChain, wasOptional: boolean) {
|
||||
return wasOptional ? isOutermostOptionalChain(node) ? getOptionalType(type) : addOptionalTypeMarker(type) : type;
|
||||
}
|
||||
|
||||
function getOptionalExpressionType(exprType: Type, expression: Expression) {
|
||||
@ -22835,7 +22847,7 @@ namespace ts {
|
||||
function checkPropertyAccessChain(node: PropertyAccessChain) {
|
||||
const leftType = checkExpression(node.expression);
|
||||
const nonOptionalType = getOptionalExpressionType(leftType, node.expression);
|
||||
return propagateOptionalTypeMarker(checkPropertyAccessExpressionOrQualifiedName(node, node.expression, checkNonNullType(nonOptionalType, node.expression), node.name), nonOptionalType !== leftType);
|
||||
return propagateOptionalTypeMarker(checkPropertyAccessExpressionOrQualifiedName(node, node.expression, checkNonNullType(nonOptionalType, node.expression), node.name), node, nonOptionalType !== leftType);
|
||||
}
|
||||
|
||||
function checkQualifiedName(node: QualifiedName) {
|
||||
@ -23267,7 +23279,7 @@ namespace ts {
|
||||
function checkElementAccessChain(node: ElementAccessChain) {
|
||||
const exprType = checkExpression(node.expression);
|
||||
const nonOptionalType = getOptionalExpressionType(exprType, node.expression);
|
||||
return propagateOptionalTypeMarker(checkElementAccessExpression(node, checkNonNullType(nonOptionalType, node.expression)), nonOptionalType !== exprType);
|
||||
return propagateOptionalTypeMarker(checkElementAccessExpression(node, checkNonNullType(nonOptionalType, node.expression)), node, nonOptionalType !== exprType);
|
||||
}
|
||||
|
||||
function checkElementAccessExpression(node: ElementAccessExpression, exprType: Type): Type {
|
||||
@ -23372,7 +23384,7 @@ namespace ts {
|
||||
// interface B extends A { (x: 'foo'): string }
|
||||
// const b: B;
|
||||
// b('foo') // <- here overloads should be processed as [(x:'foo'): string, (x: string): void]
|
||||
function reorderCandidates(signatures: readonly Signature[], result: Signature[], isOptionalCall: boolean): void {
|
||||
function reorderCandidates(signatures: readonly Signature[], result: Signature[], callChainFlags: SignatureFlags): void {
|
||||
let lastParent: Node | undefined;
|
||||
let lastSymbol: Symbol | undefined;
|
||||
let cutoffIndex = 0;
|
||||
@ -23414,7 +23426,7 @@ namespace ts {
|
||||
spliceIndex = index;
|
||||
}
|
||||
|
||||
result.splice(spliceIndex, 0, isOptionalCall ? getOptionalCallSignature(signature) : signature);
|
||||
result.splice(spliceIndex, 0, callChainFlags ? getOptionalCallSignature(signature, callChainFlags) : signature);
|
||||
}
|
||||
}
|
||||
|
||||
@ -24080,7 +24092,7 @@ namespace ts {
|
||||
return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, belowArgCount === -Infinity ? aboveArgCount : belowArgCount, argCount);
|
||||
}
|
||||
|
||||
function resolveCall(node: CallLikeExpression, signatures: readonly Signature[], candidatesOutArray: Signature[] | undefined, checkMode: CheckMode, isOptionalCall: boolean, fallbackError?: DiagnosticMessage): Signature {
|
||||
function resolveCall(node: CallLikeExpression, signatures: readonly Signature[], candidatesOutArray: Signature[] | undefined, checkMode: CheckMode, callChainFlags: SignatureFlags, fallbackError?: DiagnosticMessage): Signature {
|
||||
const isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression;
|
||||
const isDecorator = node.kind === SyntaxKind.Decorator;
|
||||
const isJsxOpeningOrSelfClosingElement = isJsxOpeningLikeElement(node);
|
||||
@ -24099,7 +24111,7 @@ namespace ts {
|
||||
|
||||
const candidates = candidatesOutArray || [];
|
||||
// reorderCandidates fills up the candidates array directly
|
||||
reorderCandidates(signatures, candidates, isOptionalCall);
|
||||
reorderCandidates(signatures, candidates, callChainFlags);
|
||||
if (!candidates.length) {
|
||||
if (reportErrors) {
|
||||
diagnostics.add(getDiagnosticForCallNode(node, Diagnostics.Call_target_does_not_contain_any_signatures));
|
||||
@ -24486,22 +24498,25 @@ namespace ts {
|
||||
const baseTypeNode = getEffectiveBaseTypeNode(getContainingClass(node)!);
|
||||
if (baseTypeNode) {
|
||||
const baseConstructors = getInstantiatedConstructorsForTypeArguments(superType, baseTypeNode.typeArguments, baseTypeNode);
|
||||
return resolveCall(node, baseConstructors, candidatesOutArray, checkMode, /*isOptional*/ false);
|
||||
return resolveCall(node, baseConstructors, candidatesOutArray, checkMode, SignatureFlags.None);
|
||||
}
|
||||
}
|
||||
return resolveUntypedCall(node);
|
||||
}
|
||||
|
||||
let isOptional: boolean;
|
||||
let callChainFlags: SignatureFlags;
|
||||
let funcType = checkExpression(node.expression);
|
||||
if (isCallChain(node)) {
|
||||
const nonOptionalType = getOptionalExpressionType(funcType, node.expression);
|
||||
isOptional = nonOptionalType !== funcType;
|
||||
callChainFlags = nonOptionalType === funcType ? SignatureFlags.None :
|
||||
isOutermostOptionalChain(node) ? SignatureFlags.IsOuterCallChain :
|
||||
SignatureFlags.IsInnerCallChain;
|
||||
funcType = nonOptionalType;
|
||||
}
|
||||
else {
|
||||
isOptional = false;
|
||||
callChainFlags = SignatureFlags.None;
|
||||
}
|
||||
|
||||
funcType = checkNonNullTypeWithReporter(
|
||||
funcType,
|
||||
node.expression,
|
||||
@ -24577,7 +24592,7 @@ namespace ts {
|
||||
return resolveErrorCall(node);
|
||||
}
|
||||
|
||||
return resolveCall(node, callSignatures, candidatesOutArray, checkMode, isOptional);
|
||||
return resolveCall(node, callSignatures, candidatesOutArray, checkMode, callChainFlags);
|
||||
}
|
||||
|
||||
function isGenericFunctionReturningFunction(signature: Signature) {
|
||||
@ -24648,7 +24663,7 @@ namespace ts {
|
||||
return resolveErrorCall(node);
|
||||
}
|
||||
|
||||
return resolveCall(node, constructSignatures, candidatesOutArray, checkMode, /*isOptional*/ false);
|
||||
return resolveCall(node, constructSignatures, candidatesOutArray, checkMode, SignatureFlags.None);
|
||||
}
|
||||
|
||||
// If expressionType's apparent type is an object type with no construct signatures but
|
||||
@ -24657,7 +24672,7 @@ namespace ts {
|
||||
// operation is Any. It is an error to have a Void this type.
|
||||
const callSignatures = getSignaturesOfType(expressionType, SignatureKind.Call);
|
||||
if (callSignatures.length) {
|
||||
const signature = resolveCall(node, callSignatures, candidatesOutArray, checkMode, /*isOptional*/ false);
|
||||
const signature = resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None);
|
||||
if (!noImplicitAny) {
|
||||
if (signature.declaration && !isJSConstructor(signature.declaration) && getReturnTypeOfSignature(signature) !== voidType) {
|
||||
error(node, Diagnostics.Only_a_void_function_can_be_called_with_the_new_keyword);
|
||||
@ -24872,7 +24887,7 @@ namespace ts {
|
||||
return resolveErrorCall(node);
|
||||
}
|
||||
|
||||
return resolveCall(node, callSignatures, candidatesOutArray, checkMode, /*isOptional*/ false);
|
||||
return resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -24935,7 +24950,7 @@ namespace ts {
|
||||
return resolveErrorCall(node);
|
||||
}
|
||||
|
||||
return resolveCall(node, callSignatures, candidatesOutArray, checkMode, /*isOptional*/ false, headMessage);
|
||||
return resolveCall(node, callSignatures, candidatesOutArray, checkMode, SignatureFlags.None, headMessage);
|
||||
}
|
||||
|
||||
function createSignatureForJSXIntrinsic(node: JsxOpeningLikeElement, result: Type): Signature {
|
||||
@ -24987,7 +25002,7 @@ namespace ts {
|
||||
return resolveErrorCall(node);
|
||||
}
|
||||
|
||||
return resolveCall(node, signatures, candidatesOutArray, checkMode, /*isOptional*/ false);
|
||||
return resolveCall(node, signatures, candidatesOutArray, checkMode, SignatureFlags.None);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -27460,6 +27475,20 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function getReturnTypeOfSingleNonGenericCallSignature(funcType: Type) {
|
||||
const signature = getSingleCallSignature(funcType);
|
||||
if (signature && !signature.typeParameters) {
|
||||
return getReturnTypeOfSignature(signature);
|
||||
}
|
||||
}
|
||||
|
||||
function getReturnTypeOfSingleNonGenericSignatureOfCallChain(expr: CallChain) {
|
||||
const funcType = checkExpression(expr.expression);
|
||||
const nonOptionalType = getOptionalExpressionType(funcType, expr.expression);
|
||||
const returnType = getReturnTypeOfSingleNonGenericCallSignature(funcType);
|
||||
return returnType && propagateOptionalTypeMarker(returnType, expr, nonOptionalType !== funcType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of an expression. Unlike checkExpression, this function is simply concerned
|
||||
* with computing the type and may not fully check all contained sub-expressions for errors.
|
||||
@ -27471,21 +27500,10 @@ namespace ts {
|
||||
// Optimize for the common case of a call to a function with a single non-generic call
|
||||
// signature where we can just fetch the return type without checking the arguments.
|
||||
if (isCallExpression(expr) && expr.expression.kind !== SyntaxKind.SuperKeyword && !isRequireCall(expr, /*checkArgumentIsStringLiteralLike*/ true) && !isSymbolOrSymbolForCall(expr)) {
|
||||
let isOptional: boolean;
|
||||
let funcType: Type;
|
||||
if (isCallChain(expr)) {
|
||||
funcType = checkExpression(expr.expression);
|
||||
const nonOptionalType = getOptionalExpressionType(funcType, expr.expression);
|
||||
isOptional = funcType !== nonOptionalType;
|
||||
funcType = checkNonNullType(nonOptionalType, expr.expression);
|
||||
}
|
||||
else {
|
||||
isOptional = false;
|
||||
funcType = checkNonNullExpression(expr.expression);
|
||||
}
|
||||
const signature = getSingleCallSignature(funcType);
|
||||
if (signature && !signature.typeParameters) {
|
||||
return propagateOptionalTypeMarker(getReturnTypeOfSignature(signature), isOptional);
|
||||
const type = isCallChain(expr) ? getReturnTypeOfSingleNonGenericSignatureOfCallChain(expr) :
|
||||
getReturnTypeOfSingleNonGenericCallSignature(checkNonNullExpression(expr.expression));
|
||||
if (type) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
else if (isAssertionExpression(expr) && !isConstTypeReference(expr.type)) {
|
||||
@ -36198,7 +36216,4 @@ namespace ts {
|
||||
return !!(s.flags & SignatureFlags.HasLiteralTypes);
|
||||
}
|
||||
|
||||
export function signatureIsOptionalCall(s: Signature) {
|
||||
return !!(s.flags & SignatureFlags.IsOptionalCall);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4673,14 +4673,17 @@ namespace ts {
|
||||
/* @internal */
|
||||
export const enum SignatureFlags {
|
||||
None = 0,
|
||||
HasRestParameter = 1 << 0, // Indicates last parameter is rest parameter
|
||||
HasLiteralTypes = 1 << 1, // Indicates signature is specialized
|
||||
IsOptionalCall = 1 << 2, // Indicates signature comes from a CallChain
|
||||
HasRestParameter = 1 << 0, // Indicates last parameter is rest parameter
|
||||
HasLiteralTypes = 1 << 1, // Indicates signature is specialized
|
||||
IsInnerCallChain = 1 << 2, // Indicates signature comes from a CallChain nested in an outer OptionalChain
|
||||
IsOuterCallChain = 1 << 3, // Indicates signature comes from a CallChain that is the outermost chain of an optional expression
|
||||
|
||||
// We do not propagate `IsOptionalCall` to instantiated signatures, as that would result in us
|
||||
// We do not propagate `IsInnerCallChain` to instantiated signatures, as that would result in us
|
||||
// attempting to add `| undefined` on each recursive call to `getReturnTypeOfSignature` when
|
||||
// instantiating the return type.
|
||||
PropagatingFlags = HasRestParameter | HasLiteralTypes,
|
||||
|
||||
CallChainFlags = IsInnerCallChain | IsOuterCallChain,
|
||||
}
|
||||
|
||||
export interface Signature {
|
||||
@ -4712,7 +4715,7 @@ namespace ts {
|
||||
/* @internal */
|
||||
canonicalSignatureCache?: Signature; // Canonical version of signature (deferred)
|
||||
/* @internal */
|
||||
optionalCallSignatureCache?: Signature; // Optional chained call version of signature (deferred)
|
||||
optionalCallSignatureCache?: { inner?: Signature, outer?: Signature }; // Optional chained call version of signature (deferred)
|
||||
/* @internal */
|
||||
isolatedSignatureType?: ObjectType; // A manufactured type that just contains the signature for purposes of signature comparison
|
||||
/* @internal */
|
||||
|
||||
@ -5947,6 +5947,11 @@ namespace ts {
|
||||
|| kind === SyntaxKind.CallExpression);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function isOptionalChainRoot(node: Node): node is OptionalChainRoot {
|
||||
return isOptionalChain(node) && !!node.questionDotToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a node is the expression preceding an optional chain (i.e. `a` in `a?.b`).
|
||||
*/
|
||||
@ -5955,6 +5960,23 @@ namespace ts {
|
||||
return isOptionalChainRoot(node.parent) && node.parent.expression === node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a node is the outermost `OptionalChain` in an ECMAScript `OptionalExpression`:
|
||||
*
|
||||
* 1. For `a?.b.c`, the outermost chain is `a?.b.c` (`c` is the end of the chain starting at `a?.`)
|
||||
* 2. For `(a?.b.c).d`, the outermost chain is `a?.b.c` (`c` is the end of the chain starting at `a?.` since parens end the chain)
|
||||
* 3. For `a?.b.c?.d`, both `a?.b.c` and `a?.b.c?.d` are outermost (`c` is the end of the chain starting at `a?.`, and `d` is
|
||||
* the end of the chain starting at `c?.`)
|
||||
* 4. For `a?.(b?.c).d`, both `b?.c` and `a?.(b?.c)d` are outermost (`c` is the end of the chain starting at `b`, and `d` is
|
||||
* the end of the chain starting at `a?.`)
|
||||
*/
|
||||
/* @internal */
|
||||
export function isOutermostOptionalChain(node: OptionalChain) {
|
||||
return !isOptionalChain(node.parent) // cases 1 and 2
|
||||
|| isOptionalChainRoot(node.parent) // case 3
|
||||
|| node !== node.parent.expression; // case 4
|
||||
}
|
||||
|
||||
export function isNullishCoalesce(node: Node) {
|
||||
return node.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>node).operatorToken.kind === SyntaxKind.QuestionQuestionToken;
|
||||
}
|
||||
@ -7276,11 +7298,6 @@ namespace ts {
|
||||
return node.kind === SyntaxKind.GetAccessor;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function isOptionalChainRoot(node: Node): node is OptionalChainRoot {
|
||||
return isOptionalChain(node) && !!node.questionDotToken;
|
||||
}
|
||||
|
||||
/** True if has jsdoc nodes attached to it. */
|
||||
/* @internal */
|
||||
// TODO: GH#19856 Would like to return `node is Node & { jsDoc: JSDoc[] }` but it causes long compile times
|
||||
|
||||
@ -45,9 +45,9 @@ const n4: number | undefined = a?.m?.({x: absorb()}); // likewise
|
||||
>a?.m : (<T>(obj: { x: T; }) => T) | undefined
|
||||
>a : { m?<T>(obj: { x: T; }): T; } | undefined
|
||||
>m : (<T>(obj: { x: T; }) => T) | undefined
|
||||
>{x: absorb()} : { x: number | undefined; }
|
||||
>x : number | undefined
|
||||
>absorb() : number | undefined
|
||||
>{x: absorb()} : { x: number; }
|
||||
>x : number
|
||||
>absorb() : number
|
||||
>absorb : <T>() => T
|
||||
|
||||
// Also a test showing `!` vs `?` for good measure
|
||||
|
||||
52
tests/baselines/reference/optionalChainingInference.js
Normal file
52
tests/baselines/reference/optionalChainingInference.js
Normal file
@ -0,0 +1,52 @@
|
||||
//// [optionalChainingInference.ts]
|
||||
// https://github.com/microsoft/TypeScript/issues/34579
|
||||
declare function unbox<T>(box: { value: T | undefined }): T;
|
||||
declare const su: string | undefined;
|
||||
declare const fnu: (() => number) | undefined;
|
||||
declare const osu: { prop: string } | undefined;
|
||||
declare const ofnu: { prop: () => number } | undefined;
|
||||
|
||||
const b1 = { value: su?.length };
|
||||
const v1: number = unbox(b1);
|
||||
|
||||
const b2 = { value: su?.length as number | undefined };
|
||||
const v2: number = unbox(b2);
|
||||
|
||||
const b3: { value: number | undefined } = { value: su?.length };
|
||||
const v3: number = unbox(b3);
|
||||
|
||||
const b4 = { value: fnu?.() };
|
||||
const v4: number = unbox(b4);
|
||||
|
||||
const b5 = { value: su?.["length"] };
|
||||
const v5: number = unbox(b5);
|
||||
|
||||
const b6 = { value: osu?.prop.length };
|
||||
const v6: number = unbox(b6);
|
||||
|
||||
const b7 = { value: osu?.prop["length"] };
|
||||
const v7: number = unbox(b7);
|
||||
|
||||
const b8 = { value: ofnu?.prop() };
|
||||
const v8: number = unbox(b8);
|
||||
|
||||
|
||||
|
||||
//// [optionalChainingInference.js]
|
||||
var _a, _b, _c, _d, _e, _f, _g, _h;
|
||||
var b1 = { value: (_a = su) === null || _a === void 0 ? void 0 : _a.length };
|
||||
var v1 = unbox(b1);
|
||||
var b2 = { value: (_b = su) === null || _b === void 0 ? void 0 : _b.length };
|
||||
var v2 = unbox(b2);
|
||||
var b3 = { value: (_c = su) === null || _c === void 0 ? void 0 : _c.length };
|
||||
var v3 = unbox(b3);
|
||||
var b4 = { value: (_d = fnu) === null || _d === void 0 ? void 0 : _d() };
|
||||
var v4 = unbox(b4);
|
||||
var b5 = { value: (_e = su) === null || _e === void 0 ? void 0 : _e["length"] };
|
||||
var v5 = unbox(b5);
|
||||
var b6 = { value: (_f = osu) === null || _f === void 0 ? void 0 : _f.prop.length };
|
||||
var v6 = unbox(b6);
|
||||
var b7 = { value: (_g = osu) === null || _g === void 0 ? void 0 : _g.prop["length"] };
|
||||
var v7 = unbox(b7);
|
||||
var b8 = { value: (_h = ofnu) === null || _h === void 0 ? void 0 : _h.prop() };
|
||||
var v8 = unbox(b8);
|
||||
122
tests/baselines/reference/optionalChainingInference.symbols
Normal file
122
tests/baselines/reference/optionalChainingInference.symbols
Normal file
@ -0,0 +1,122 @@
|
||||
=== tests/cases/conformance/expressions/optionalChaining/optionalChainingInference.ts ===
|
||||
// https://github.com/microsoft/TypeScript/issues/34579
|
||||
declare function unbox<T>(box: { value: T | undefined }): T;
|
||||
>unbox : Symbol(unbox, Decl(optionalChainingInference.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(optionalChainingInference.ts, 1, 23))
|
||||
>box : Symbol(box, Decl(optionalChainingInference.ts, 1, 26))
|
||||
>value : Symbol(value, Decl(optionalChainingInference.ts, 1, 32))
|
||||
>T : Symbol(T, Decl(optionalChainingInference.ts, 1, 23))
|
||||
>T : Symbol(T, Decl(optionalChainingInference.ts, 1, 23))
|
||||
|
||||
declare const su: string | undefined;
|
||||
>su : Symbol(su, Decl(optionalChainingInference.ts, 2, 13))
|
||||
|
||||
declare const fnu: (() => number) | undefined;
|
||||
>fnu : Symbol(fnu, Decl(optionalChainingInference.ts, 3, 13))
|
||||
|
||||
declare const osu: { prop: string } | undefined;
|
||||
>osu : Symbol(osu, Decl(optionalChainingInference.ts, 4, 13))
|
||||
>prop : Symbol(prop, Decl(optionalChainingInference.ts, 4, 20))
|
||||
|
||||
declare const ofnu: { prop: () => number } | undefined;
|
||||
>ofnu : Symbol(ofnu, Decl(optionalChainingInference.ts, 5, 13))
|
||||
>prop : Symbol(prop, Decl(optionalChainingInference.ts, 5, 21))
|
||||
|
||||
const b1 = { value: su?.length };
|
||||
>b1 : Symbol(b1, Decl(optionalChainingInference.ts, 7, 5))
|
||||
>value : Symbol(value, Decl(optionalChainingInference.ts, 7, 12))
|
||||
>su?.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
|
||||
>su : Symbol(su, Decl(optionalChainingInference.ts, 2, 13))
|
||||
>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
const v1: number = unbox(b1);
|
||||
>v1 : Symbol(v1, Decl(optionalChainingInference.ts, 8, 5))
|
||||
>unbox : Symbol(unbox, Decl(optionalChainingInference.ts, 0, 0))
|
||||
>b1 : Symbol(b1, Decl(optionalChainingInference.ts, 7, 5))
|
||||
|
||||
const b2 = { value: su?.length as number | undefined };
|
||||
>b2 : Symbol(b2, Decl(optionalChainingInference.ts, 10, 5))
|
||||
>value : Symbol(value, Decl(optionalChainingInference.ts, 10, 12))
|
||||
>su?.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
|
||||
>su : Symbol(su, Decl(optionalChainingInference.ts, 2, 13))
|
||||
>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
const v2: number = unbox(b2);
|
||||
>v2 : Symbol(v2, Decl(optionalChainingInference.ts, 11, 5))
|
||||
>unbox : Symbol(unbox, Decl(optionalChainingInference.ts, 0, 0))
|
||||
>b2 : Symbol(b2, Decl(optionalChainingInference.ts, 10, 5))
|
||||
|
||||
const b3: { value: number | undefined } = { value: su?.length };
|
||||
>b3 : Symbol(b3, Decl(optionalChainingInference.ts, 13, 5))
|
||||
>value : Symbol(value, Decl(optionalChainingInference.ts, 13, 11))
|
||||
>value : Symbol(value, Decl(optionalChainingInference.ts, 13, 43))
|
||||
>su?.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
|
||||
>su : Symbol(su, Decl(optionalChainingInference.ts, 2, 13))
|
||||
>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
const v3: number = unbox(b3);
|
||||
>v3 : Symbol(v3, Decl(optionalChainingInference.ts, 14, 5))
|
||||
>unbox : Symbol(unbox, Decl(optionalChainingInference.ts, 0, 0))
|
||||
>b3 : Symbol(b3, Decl(optionalChainingInference.ts, 13, 5))
|
||||
|
||||
const b4 = { value: fnu?.() };
|
||||
>b4 : Symbol(b4, Decl(optionalChainingInference.ts, 16, 5))
|
||||
>value : Symbol(value, Decl(optionalChainingInference.ts, 16, 12))
|
||||
>fnu : Symbol(fnu, Decl(optionalChainingInference.ts, 3, 13))
|
||||
|
||||
const v4: number = unbox(b4);
|
||||
>v4 : Symbol(v4, Decl(optionalChainingInference.ts, 17, 5))
|
||||
>unbox : Symbol(unbox, Decl(optionalChainingInference.ts, 0, 0))
|
||||
>b4 : Symbol(b4, Decl(optionalChainingInference.ts, 16, 5))
|
||||
|
||||
const b5 = { value: su?.["length"] };
|
||||
>b5 : Symbol(b5, Decl(optionalChainingInference.ts, 19, 5))
|
||||
>value : Symbol(value, Decl(optionalChainingInference.ts, 19, 12))
|
||||
>su : Symbol(su, Decl(optionalChainingInference.ts, 2, 13))
|
||||
>"length" : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
const v5: number = unbox(b5);
|
||||
>v5 : Symbol(v5, Decl(optionalChainingInference.ts, 20, 5))
|
||||
>unbox : Symbol(unbox, Decl(optionalChainingInference.ts, 0, 0))
|
||||
>b5 : Symbol(b5, Decl(optionalChainingInference.ts, 19, 5))
|
||||
|
||||
const b6 = { value: osu?.prop.length };
|
||||
>b6 : Symbol(b6, Decl(optionalChainingInference.ts, 22, 5))
|
||||
>value : Symbol(value, Decl(optionalChainingInference.ts, 22, 12))
|
||||
>osu?.prop.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
|
||||
>osu?.prop : Symbol(prop, Decl(optionalChainingInference.ts, 4, 20))
|
||||
>osu : Symbol(osu, Decl(optionalChainingInference.ts, 4, 13))
|
||||
>prop : Symbol(prop, Decl(optionalChainingInference.ts, 4, 20))
|
||||
>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
const v6: number = unbox(b6);
|
||||
>v6 : Symbol(v6, Decl(optionalChainingInference.ts, 23, 5))
|
||||
>unbox : Symbol(unbox, Decl(optionalChainingInference.ts, 0, 0))
|
||||
>b6 : Symbol(b6, Decl(optionalChainingInference.ts, 22, 5))
|
||||
|
||||
const b7 = { value: osu?.prop["length"] };
|
||||
>b7 : Symbol(b7, Decl(optionalChainingInference.ts, 25, 5))
|
||||
>value : Symbol(value, Decl(optionalChainingInference.ts, 25, 12))
|
||||
>osu?.prop : Symbol(prop, Decl(optionalChainingInference.ts, 4, 20))
|
||||
>osu : Symbol(osu, Decl(optionalChainingInference.ts, 4, 13))
|
||||
>prop : Symbol(prop, Decl(optionalChainingInference.ts, 4, 20))
|
||||
>"length" : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
const v7: number = unbox(b7);
|
||||
>v7 : Symbol(v7, Decl(optionalChainingInference.ts, 26, 5))
|
||||
>unbox : Symbol(unbox, Decl(optionalChainingInference.ts, 0, 0))
|
||||
>b7 : Symbol(b7, Decl(optionalChainingInference.ts, 25, 5))
|
||||
|
||||
const b8 = { value: ofnu?.prop() };
|
||||
>b8 : Symbol(b8, Decl(optionalChainingInference.ts, 28, 5))
|
||||
>value : Symbol(value, Decl(optionalChainingInference.ts, 28, 12))
|
||||
>ofnu?.prop : Symbol(prop, Decl(optionalChainingInference.ts, 5, 21))
|
||||
>ofnu : Symbol(ofnu, Decl(optionalChainingInference.ts, 5, 13))
|
||||
>prop : Symbol(prop, Decl(optionalChainingInference.ts, 5, 21))
|
||||
|
||||
const v8: number = unbox(b8);
|
||||
>v8 : Symbol(v8, Decl(optionalChainingInference.ts, 29, 5))
|
||||
>unbox : Symbol(unbox, Decl(optionalChainingInference.ts, 0, 0))
|
||||
>b8 : Symbol(b8, Decl(optionalChainingInference.ts, 28, 5))
|
||||
|
||||
|
||||
140
tests/baselines/reference/optionalChainingInference.types
Normal file
140
tests/baselines/reference/optionalChainingInference.types
Normal file
@ -0,0 +1,140 @@
|
||||
=== tests/cases/conformance/expressions/optionalChaining/optionalChainingInference.ts ===
|
||||
// https://github.com/microsoft/TypeScript/issues/34579
|
||||
declare function unbox<T>(box: { value: T | undefined }): T;
|
||||
>unbox : <T>(box: { value: T; }) => T
|
||||
>box : { value: T; }
|
||||
>value : T
|
||||
|
||||
declare const su: string | undefined;
|
||||
>su : string
|
||||
|
||||
declare const fnu: (() => number) | undefined;
|
||||
>fnu : () => number
|
||||
|
||||
declare const osu: { prop: string } | undefined;
|
||||
>osu : { prop: string; }
|
||||
>prop : string
|
||||
|
||||
declare const ofnu: { prop: () => number } | undefined;
|
||||
>ofnu : { prop: () => number; }
|
||||
>prop : () => number
|
||||
|
||||
const b1 = { value: su?.length };
|
||||
>b1 : { value: number; }
|
||||
>{ value: su?.length } : { value: number; }
|
||||
>value : number
|
||||
>su?.length : number
|
||||
>su : string
|
||||
>length : number
|
||||
|
||||
const v1: number = unbox(b1);
|
||||
>v1 : number
|
||||
>unbox(b1) : number
|
||||
>unbox : <T>(box: { value: T; }) => T
|
||||
>b1 : { value: number; }
|
||||
|
||||
const b2 = { value: su?.length as number | undefined };
|
||||
>b2 : { value: number; }
|
||||
>{ value: su?.length as number | undefined } : { value: number; }
|
||||
>value : number
|
||||
>su?.length as number | undefined : number
|
||||
>su?.length : number
|
||||
>su : string
|
||||
>length : number
|
||||
|
||||
const v2: number = unbox(b2);
|
||||
>v2 : number
|
||||
>unbox(b2) : number
|
||||
>unbox : <T>(box: { value: T; }) => T
|
||||
>b2 : { value: number; }
|
||||
|
||||
const b3: { value: number | undefined } = { value: su?.length };
|
||||
>b3 : { value: number; }
|
||||
>value : number
|
||||
>{ value: su?.length } : { value: number; }
|
||||
>value : number
|
||||
>su?.length : number
|
||||
>su : string
|
||||
>length : number
|
||||
|
||||
const v3: number = unbox(b3);
|
||||
>v3 : number
|
||||
>unbox(b3) : number
|
||||
>unbox : <T>(box: { value: T; }) => T
|
||||
>b3 : { value: number; }
|
||||
|
||||
const b4 = { value: fnu?.() };
|
||||
>b4 : { value: number; }
|
||||
>{ value: fnu?.() } : { value: number; }
|
||||
>value : number
|
||||
>fnu?.() : number
|
||||
>fnu : () => number
|
||||
|
||||
const v4: number = unbox(b4);
|
||||
>v4 : number
|
||||
>unbox(b4) : number
|
||||
>unbox : <T>(box: { value: T; }) => T
|
||||
>b4 : { value: number; }
|
||||
|
||||
const b5 = { value: su?.["length"] };
|
||||
>b5 : { value: number; }
|
||||
>{ value: su?.["length"] } : { value: number; }
|
||||
>value : number
|
||||
>su?.["length"] : number
|
||||
>su : string
|
||||
>"length" : "length"
|
||||
|
||||
const v5: number = unbox(b5);
|
||||
>v5 : number
|
||||
>unbox(b5) : number
|
||||
>unbox : <T>(box: { value: T; }) => T
|
||||
>b5 : { value: number; }
|
||||
|
||||
const b6 = { value: osu?.prop.length };
|
||||
>b6 : { value: number; }
|
||||
>{ value: osu?.prop.length } : { value: number; }
|
||||
>value : number
|
||||
>osu?.prop.length : number
|
||||
>osu?.prop : string
|
||||
>osu : { prop: string; }
|
||||
>prop : string
|
||||
>length : number
|
||||
|
||||
const v6: number = unbox(b6);
|
||||
>v6 : number
|
||||
>unbox(b6) : number
|
||||
>unbox : <T>(box: { value: T; }) => T
|
||||
>b6 : { value: number; }
|
||||
|
||||
const b7 = { value: osu?.prop["length"] };
|
||||
>b7 : { value: number; }
|
||||
>{ value: osu?.prop["length"] } : { value: number; }
|
||||
>value : number
|
||||
>osu?.prop["length"] : number
|
||||
>osu?.prop : string
|
||||
>osu : { prop: string; }
|
||||
>prop : string
|
||||
>"length" : "length"
|
||||
|
||||
const v7: number = unbox(b7);
|
||||
>v7 : number
|
||||
>unbox(b7) : number
|
||||
>unbox : <T>(box: { value: T; }) => T
|
||||
>b7 : { value: number; }
|
||||
|
||||
const b8 = { value: ofnu?.prop() };
|
||||
>b8 : { value: number; }
|
||||
>{ value: ofnu?.prop() } : { value: number; }
|
||||
>value : number
|
||||
>ofnu?.prop() : number
|
||||
>ofnu?.prop : () => number
|
||||
>ofnu : { prop: () => number; }
|
||||
>prop : () => number
|
||||
|
||||
const v8: number = unbox(b8);
|
||||
>v8 : number
|
||||
>unbox(b8) : number
|
||||
>unbox : <T>(box: { value: T; }) => T
|
||||
>b8 : { value: number; }
|
||||
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
// https://github.com/microsoft/TypeScript/issues/34579
|
||||
declare function unbox<T>(box: { value: T | undefined }): T;
|
||||
declare const su: string | undefined;
|
||||
declare const fnu: (() => number) | undefined;
|
||||
declare const osu: { prop: string } | undefined;
|
||||
declare const ofnu: { prop: () => number } | undefined;
|
||||
|
||||
const b1 = { value: su?.length };
|
||||
const v1: number = unbox(b1);
|
||||
|
||||
const b2 = { value: su?.length as number | undefined };
|
||||
const v2: number = unbox(b2);
|
||||
|
||||
const b3: { value: number | undefined } = { value: su?.length };
|
||||
const v3: number = unbox(b3);
|
||||
|
||||
const b4 = { value: fnu?.() };
|
||||
const v4: number = unbox(b4);
|
||||
|
||||
const b5 = { value: su?.["length"] };
|
||||
const v5: number = unbox(b5);
|
||||
|
||||
const b6 = { value: osu?.prop.length };
|
||||
const v6: number = unbox(b6);
|
||||
|
||||
const b7 = { value: osu?.prop["length"] };
|
||||
const v7: number = unbox(b7);
|
||||
|
||||
const b8 = { value: ofnu?.prop() };
|
||||
const v8: number = unbox(b8);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user