mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-04-17 01:49:41 -05:00
Add test case for excess property checking fix in destructuring contexts
Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com>
This commit is contained in:
@@ -36065,16 +36065,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
const arg = args[i];
|
||||
if (arg.kind !== SyntaxKind.OmittedExpression) {
|
||||
const paramType = getTypeAtPosition(signature, i);
|
||||
const argType = checkExpressionWithContextualType(arg, paramType, /*inferenceContext*/ undefined, checkMode);
|
||||
// If one or more arguments are still excluded (as indicated by CheckMode.SkipContextSensitive),
|
||||
// we obtain the regular type of any object literal arguments because we may not have inferred complete
|
||||
// parameter types yet and therefore excess property checks may yield false positives (see #17041).
|
||||
// Also skip fresh literal checking when the call is in a destructuring context to avoid inappropriate
|
||||
// excess property checking (see #41548).
|
||||
const shouldSkipFreshness = (checkMode & CheckMode.SkipContextSensitive) ||
|
||||
(isCallExpression(node) && isCallInDestructuringContext(node));
|
||||
const checkArgType = shouldSkipFreshness ? getRegularTypeOfObjectLiteral(argType) : argType;
|
||||
const effectiveCheckArgumentNode = getEffectiveCheckNode(arg);
|
||||
const argType = checkExpressionWithContextualType(arg, paramType, /*inferenceContext*/ undefined, checkMode);
|
||||
// If one or more arguments are still excluded (as indicated by CheckMode.SkipContextSensitive),
|
||||
// we obtain the regular type of any object literal arguments because we may not have inferred complete
|
||||
// parameter types yet and therefore excess property checks may yield false positives (see #17041).
|
||||
// Also skip fresh literal checking when the call is in a destructuring context to avoid inappropriate
|
||||
// excess property checking (see #41548).
|
||||
const shouldSkipFreshness = (checkMode & CheckMode.SkipContextSensitive) ||
|
||||
(isCallExpression(node) && isCallInDestructuringContext(node));
|
||||
const checkArgType = shouldSkipFreshness ? getRegularTypeOfObjectLiteral(argType) : argType;
|
||||
const effectiveCheckArgumentNode = getEffectiveCheckNode(arg);
|
||||
if (!checkTypeRelatedToAndOptionallyElaborate(checkArgType, paramType, relation, reportErrors ? effectiveCheckArgumentNode : undefined, effectiveCheckArgumentNode, headMessage, containingMessageChain, errorOutputContainer)) {
|
||||
Debug.assert(!reportErrors || !!errorOutputContainer.errors, "parameter should have errors when reporting errors");
|
||||
maybeAddMissingAwaitInfo(arg, checkArgType, paramType);
|
||||
@@ -36419,23 +36419,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return createDiagnosticForNodeArrayFromMessageChain(getSourceFileOfNode(node), typeArguments, chain);
|
||||
}
|
||||
return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, belowArgCount === -Infinity ? aboveArgCount : belowArgCount, argCount);
|
||||
}
|
||||
|
||||
function isCallInDestructuringContext(node: CallLikeExpression): boolean {
|
||||
// Check if this call expression is used as the initializer in a variable declaration with a destructuring pattern
|
||||
const parent = node.parent;
|
||||
if (parent && isVariableDeclaration(parent) && parent.initializer === node) {
|
||||
return isBindingPattern(parent.name);
|
||||
}
|
||||
|
||||
// Check for assignment expressions: [a, b] = foo()
|
||||
if (parent && isBinaryExpression(parent) && parent.operatorToken.kind === SyntaxKind.EqualsToken && parent.right === node) {
|
||||
return isArrayLiteralExpression(parent.left) || isObjectLiteralExpression(parent.left);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function isCallInDestructuringContext(node: CallLikeExpression): boolean {
|
||||
// Check if this call expression is used as the initializer in a variable declaration with a destructuring pattern
|
||||
const parent = node.parent;
|
||||
if (parent && isVariableDeclaration(parent) && parent.initializer === node) {
|
||||
return isBindingPattern(parent.name);
|
||||
}
|
||||
|
||||
// Check for assignment expressions: [a, b] = foo()
|
||||
if (parent && isBinaryExpression(parent) && parent.operatorToken.kind === SyntaxKind.EqualsToken && parent.right === node) {
|
||||
return isArrayLiteralExpression(parent.left) || isObjectLiteralExpression(parent.left);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function resolveCall(node: CallLikeExpression, signatures: readonly Signature[], candidatesOutArray: Signature[] | undefined, checkMode: CheckMode, callChainFlags: SignatureFlags, headMessage?: DiagnosticMessage): Signature {
|
||||
const isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression;
|
||||
const isDecorator = node.kind === SyntaxKind.Decorator;
|
||||
@@ -36507,18 +36507,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
//
|
||||
// For a decorator, no arguments are susceptible to contextual typing due to the fact
|
||||
// decorators are applied to a declaration by the emitter, and not to an expression.
|
||||
const isSingleNonGenericCandidate = candidates.length === 1 && !candidates[0].typeParameters;
|
||||
let shouldSkipContextSensitive = !isDecorator && !isSingleNonGenericCandidate && some(args, isContextSensitive);
|
||||
|
||||
// Also skip context sensitive checking when the call is used in a destructuring context
|
||||
// to avoid inappropriate excess property checking on object literal arguments
|
||||
const isInDestructuring = !isDecorator && isCallInDestructuringContext(node);
|
||||
if (isInDestructuring && !shouldSkipContextSensitive) {
|
||||
shouldSkipContextSensitive = true;
|
||||
}
|
||||
|
||||
if (shouldSkipContextSensitive) {
|
||||
argCheckMode = CheckMode.SkipContextSensitive;
|
||||
const isSingleNonGenericCandidate = candidates.length === 1 && !candidates[0].typeParameters;
|
||||
let shouldSkipContextSensitive = !isDecorator && !isSingleNonGenericCandidate && some(args, isContextSensitive);
|
||||
|
||||
// Also skip context sensitive checking when the call is used in a destructuring context
|
||||
// to avoid inappropriate excess property checking on object literal arguments
|
||||
const isInDestructuring = !isDecorator && isCallInDestructuringContext(node);
|
||||
if (isInDestructuring && !shouldSkipContextSensitive) {
|
||||
shouldSkipContextSensitive = true;
|
||||
}
|
||||
|
||||
if (shouldSkipContextSensitive) {
|
||||
argCheckMode = CheckMode.SkipContextSensitive;
|
||||
}
|
||||
|
||||
// If we are in signature help, a trailing comma indicates that we intend to provide another argument,
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
excessPropertyCheckingInDestructuring.ts(14,30): error TS2322: Type '"invalid"' is not assignable to type '"a" | "b"'.
|
||||
excessPropertyCheckingInDestructuring.ts(15,30): error TS2322: Type '"invalid"' is not assignable to type '"a" | "b"'.
|
||||
excessPropertyCheckingInDestructuring.ts(19,38): error TS2353: Object literal may only specify known properties, and 'day' does not exist in type '{ dataType: "a" | "b"; }'.
|
||||
|
||||
|
||||
==== excessPropertyCheckingInDestructuring.ts (3 errors) ====
|
||||
declare function foo<T extends { dataType: 'a' | 'b' }>(template: T): [T, any, any];
|
||||
declare function bar(template: { dataType: 'a' | 'b' }): [any, any, any];
|
||||
|
||||
// These should work without excess property errors - destructuring contexts
|
||||
const [, ,] = foo({ dataType: 'a', day: 0 });
|
||||
const [, , t] = foo({ dataType: 'a', day: 0 });
|
||||
const [x, y, z] = foo({ dataType: 'a', day: 0 });
|
||||
|
||||
const [, ,] = bar({ dataType: 'a', day: 0 });
|
||||
const [, , u] = bar({ dataType: 'a', day: 0 });
|
||||
const [a, b, c] = bar({ dataType: 'a', day: 0 });
|
||||
|
||||
// These should still report legitimate type errors
|
||||
const [, , invalid1] = foo({ dataType: 'invalid' });
|
||||
~~~~~~~~
|
||||
!!! error TS2322: Type '"invalid"' is not assignable to type '"a" | "b"'.
|
||||
!!! related TS6500 excessPropertyCheckingInDestructuring.ts:1:34: The expected type comes from property 'dataType' which is declared here on type '{ dataType: "a" | "b"; }'
|
||||
const [, , invalid2] = bar({ dataType: 'invalid' });
|
||||
~~~~~~~~
|
||||
!!! error TS2322: Type '"invalid"' is not assignable to type '"a" | "b"'.
|
||||
!!! related TS6500 excessPropertyCheckingInDestructuring.ts:2:34: The expected type comes from property 'dataType' which is declared here on type '{ dataType: "a" | "b"; }'
|
||||
|
||||
// Non-destructuring cases - generic function should work, non-generic should error
|
||||
const result1 = foo({ dataType: 'a', day: 0 }); // OK - generic function
|
||||
const result2 = bar({ dataType: 'a', day: 0 }); // Error - non-generic with excess property
|
||||
~~~
|
||||
!!! error TS2353: Object literal may only specify known properties, and 'day' does not exist in type '{ dataType: "a" | "b"; }'.
|
||||
|
||||
// Assignment destructuring should also work
|
||||
let d, e, f: any;
|
||||
[d, e, f] = foo({ dataType: 'a', day: 0 });
|
||||
@@ -0,0 +1,46 @@
|
||||
//// [tests/cases/compiler/excessPropertyCheckingInDestructuring.ts] ////
|
||||
|
||||
//// [excessPropertyCheckingInDestructuring.ts]
|
||||
declare function foo<T extends { dataType: 'a' | 'b' }>(template: T): [T, any, any];
|
||||
declare function bar(template: { dataType: 'a' | 'b' }): [any, any, any];
|
||||
|
||||
// These should work without excess property errors - destructuring contexts
|
||||
const [, ,] = foo({ dataType: 'a', day: 0 });
|
||||
const [, , t] = foo({ dataType: 'a', day: 0 });
|
||||
const [x, y, z] = foo({ dataType: 'a', day: 0 });
|
||||
|
||||
const [, ,] = bar({ dataType: 'a', day: 0 });
|
||||
const [, , u] = bar({ dataType: 'a', day: 0 });
|
||||
const [a, b, c] = bar({ dataType: 'a', day: 0 });
|
||||
|
||||
// These should still report legitimate type errors
|
||||
const [, , invalid1] = foo({ dataType: 'invalid' });
|
||||
const [, , invalid2] = bar({ dataType: 'invalid' });
|
||||
|
||||
// Non-destructuring cases - generic function should work, non-generic should error
|
||||
const result1 = foo({ dataType: 'a', day: 0 }); // OK - generic function
|
||||
const result2 = bar({ dataType: 'a', day: 0 }); // Error - non-generic with excess property
|
||||
|
||||
// Assignment destructuring should also work
|
||||
let d, e, f: any;
|
||||
[d, e, f] = foo({ dataType: 'a', day: 0 });
|
||||
|
||||
//// [excessPropertyCheckingInDestructuring.js]
|
||||
"use strict";
|
||||
var _a;
|
||||
// These should work without excess property errors - destructuring contexts
|
||||
var _b = foo({ dataType: 'a', day: 0 });
|
||||
var _c = foo({ dataType: 'a', day: 0 }), t = _c[2];
|
||||
var _d = foo({ dataType: 'a', day: 0 }), x = _d[0], y = _d[1], z = _d[2];
|
||||
var _e = bar({ dataType: 'a', day: 0 });
|
||||
var _f = bar({ dataType: 'a', day: 0 }), u = _f[2];
|
||||
var _g = bar({ dataType: 'a', day: 0 }), a = _g[0], b = _g[1], c = _g[2];
|
||||
// These should still report legitimate type errors
|
||||
var _h = foo({ dataType: 'invalid' }), invalid1 = _h[2];
|
||||
var _j = bar({ dataType: 'invalid' }), invalid2 = _j[2];
|
||||
// Non-destructuring cases - generic function should work, non-generic should error
|
||||
var result1 = foo({ dataType: 'a', day: 0 }); // OK - generic function
|
||||
var result2 = bar({ dataType: 'a', day: 0 }); // Error - non-generic with excess property
|
||||
// Assignment destructuring should also work
|
||||
var d, e, f;
|
||||
_a = foo({ dataType: 'a', day: 0 }), d = _a[0], e = _a[1], f = _a[2];
|
||||
@@ -0,0 +1,93 @@
|
||||
//// [tests/cases/compiler/excessPropertyCheckingInDestructuring.ts] ////
|
||||
|
||||
=== excessPropertyCheckingInDestructuring.ts ===
|
||||
declare function foo<T extends { dataType: 'a' | 'b' }>(template: T): [T, any, any];
|
||||
>foo : Symbol(foo, Decl(excessPropertyCheckingInDestructuring.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(excessPropertyCheckingInDestructuring.ts, 0, 21))
|
||||
>dataType : Symbol(dataType, Decl(excessPropertyCheckingInDestructuring.ts, 0, 32))
|
||||
>template : Symbol(template, Decl(excessPropertyCheckingInDestructuring.ts, 0, 56))
|
||||
>T : Symbol(T, Decl(excessPropertyCheckingInDestructuring.ts, 0, 21))
|
||||
>T : Symbol(T, Decl(excessPropertyCheckingInDestructuring.ts, 0, 21))
|
||||
|
||||
declare function bar(template: { dataType: 'a' | 'b' }): [any, any, any];
|
||||
>bar : Symbol(bar, Decl(excessPropertyCheckingInDestructuring.ts, 0, 84))
|
||||
>template : Symbol(template, Decl(excessPropertyCheckingInDestructuring.ts, 1, 21))
|
||||
>dataType : Symbol(dataType, Decl(excessPropertyCheckingInDestructuring.ts, 1, 32))
|
||||
|
||||
// These should work without excess property errors - destructuring contexts
|
||||
const [, ,] = foo({ dataType: 'a', day: 0 });
|
||||
>foo : Symbol(foo, Decl(excessPropertyCheckingInDestructuring.ts, 0, 0))
|
||||
>dataType : Symbol(dataType, Decl(excessPropertyCheckingInDestructuring.ts, 4, 19))
|
||||
>day : Symbol(day, Decl(excessPropertyCheckingInDestructuring.ts, 4, 34))
|
||||
|
||||
const [, , t] = foo({ dataType: 'a', day: 0 });
|
||||
>t : Symbol(t, Decl(excessPropertyCheckingInDestructuring.ts, 5, 10))
|
||||
>foo : Symbol(foo, Decl(excessPropertyCheckingInDestructuring.ts, 0, 0))
|
||||
>dataType : Symbol(dataType, Decl(excessPropertyCheckingInDestructuring.ts, 5, 21))
|
||||
>day : Symbol(day, Decl(excessPropertyCheckingInDestructuring.ts, 5, 36))
|
||||
|
||||
const [x, y, z] = foo({ dataType: 'a', day: 0 });
|
||||
>x : Symbol(x, Decl(excessPropertyCheckingInDestructuring.ts, 6, 7))
|
||||
>y : Symbol(y, Decl(excessPropertyCheckingInDestructuring.ts, 6, 9))
|
||||
>z : Symbol(z, Decl(excessPropertyCheckingInDestructuring.ts, 6, 12))
|
||||
>foo : Symbol(foo, Decl(excessPropertyCheckingInDestructuring.ts, 0, 0))
|
||||
>dataType : Symbol(dataType, Decl(excessPropertyCheckingInDestructuring.ts, 6, 23))
|
||||
>day : Symbol(day, Decl(excessPropertyCheckingInDestructuring.ts, 6, 38))
|
||||
|
||||
const [, ,] = bar({ dataType: 'a', day: 0 });
|
||||
>bar : Symbol(bar, Decl(excessPropertyCheckingInDestructuring.ts, 0, 84))
|
||||
>dataType : Symbol(dataType, Decl(excessPropertyCheckingInDestructuring.ts, 8, 19))
|
||||
>day : Symbol(day, Decl(excessPropertyCheckingInDestructuring.ts, 8, 34))
|
||||
|
||||
const [, , u] = bar({ dataType: 'a', day: 0 });
|
||||
>u : Symbol(u, Decl(excessPropertyCheckingInDestructuring.ts, 9, 10))
|
||||
>bar : Symbol(bar, Decl(excessPropertyCheckingInDestructuring.ts, 0, 84))
|
||||
>dataType : Symbol(dataType, Decl(excessPropertyCheckingInDestructuring.ts, 9, 21))
|
||||
>day : Symbol(day, Decl(excessPropertyCheckingInDestructuring.ts, 9, 36))
|
||||
|
||||
const [a, b, c] = bar({ dataType: 'a', day: 0 });
|
||||
>a : Symbol(a, Decl(excessPropertyCheckingInDestructuring.ts, 10, 7))
|
||||
>b : Symbol(b, Decl(excessPropertyCheckingInDestructuring.ts, 10, 9))
|
||||
>c : Symbol(c, Decl(excessPropertyCheckingInDestructuring.ts, 10, 12))
|
||||
>bar : Symbol(bar, Decl(excessPropertyCheckingInDestructuring.ts, 0, 84))
|
||||
>dataType : Symbol(dataType, Decl(excessPropertyCheckingInDestructuring.ts, 10, 23))
|
||||
>day : Symbol(day, Decl(excessPropertyCheckingInDestructuring.ts, 10, 38))
|
||||
|
||||
// These should still report legitimate type errors
|
||||
const [, , invalid1] = foo({ dataType: 'invalid' });
|
||||
>invalid1 : Symbol(invalid1, Decl(excessPropertyCheckingInDestructuring.ts, 13, 10))
|
||||
>foo : Symbol(foo, Decl(excessPropertyCheckingInDestructuring.ts, 0, 0))
|
||||
>dataType : Symbol(dataType, Decl(excessPropertyCheckingInDestructuring.ts, 13, 28))
|
||||
|
||||
const [, , invalid2] = bar({ dataType: 'invalid' });
|
||||
>invalid2 : Symbol(invalid2, Decl(excessPropertyCheckingInDestructuring.ts, 14, 10))
|
||||
>bar : Symbol(bar, Decl(excessPropertyCheckingInDestructuring.ts, 0, 84))
|
||||
>dataType : Symbol(dataType, Decl(excessPropertyCheckingInDestructuring.ts, 14, 28))
|
||||
|
||||
// Non-destructuring cases - generic function should work, non-generic should error
|
||||
const result1 = foo({ dataType: 'a', day: 0 }); // OK - generic function
|
||||
>result1 : Symbol(result1, Decl(excessPropertyCheckingInDestructuring.ts, 17, 5))
|
||||
>foo : Symbol(foo, Decl(excessPropertyCheckingInDestructuring.ts, 0, 0))
|
||||
>dataType : Symbol(dataType, Decl(excessPropertyCheckingInDestructuring.ts, 17, 21))
|
||||
>day : Symbol(day, Decl(excessPropertyCheckingInDestructuring.ts, 17, 36))
|
||||
|
||||
const result2 = bar({ dataType: 'a', day: 0 }); // Error - non-generic with excess property
|
||||
>result2 : Symbol(result2, Decl(excessPropertyCheckingInDestructuring.ts, 18, 5))
|
||||
>bar : Symbol(bar, Decl(excessPropertyCheckingInDestructuring.ts, 0, 84))
|
||||
>dataType : Symbol(dataType, Decl(excessPropertyCheckingInDestructuring.ts, 18, 21))
|
||||
>day : Symbol(day, Decl(excessPropertyCheckingInDestructuring.ts, 18, 36))
|
||||
|
||||
// Assignment destructuring should also work
|
||||
let d, e, f: any;
|
||||
>d : Symbol(d, Decl(excessPropertyCheckingInDestructuring.ts, 21, 3))
|
||||
>e : Symbol(e, Decl(excessPropertyCheckingInDestructuring.ts, 21, 6))
|
||||
>f : Symbol(f, Decl(excessPropertyCheckingInDestructuring.ts, 21, 9))
|
||||
|
||||
[d, e, f] = foo({ dataType: 'a', day: 0 });
|
||||
>d : Symbol(d, Decl(excessPropertyCheckingInDestructuring.ts, 21, 3))
|
||||
>e : Symbol(e, Decl(excessPropertyCheckingInDestructuring.ts, 21, 6))
|
||||
>f : Symbol(f, Decl(excessPropertyCheckingInDestructuring.ts, 21, 9))
|
||||
>foo : Symbol(foo, Decl(excessPropertyCheckingInDestructuring.ts, 0, 0))
|
||||
>dataType : Symbol(dataType, Decl(excessPropertyCheckingInDestructuring.ts, 22, 17))
|
||||
>day : Symbol(day, Decl(excessPropertyCheckingInDestructuring.ts, 22, 32))
|
||||
|
||||
@@ -0,0 +1,257 @@
|
||||
//// [tests/cases/compiler/excessPropertyCheckingInDestructuring.ts] ////
|
||||
|
||||
=== excessPropertyCheckingInDestructuring.ts ===
|
||||
declare function foo<T extends { dataType: 'a' | 'b' }>(template: T): [T, any, any];
|
||||
>foo : <T extends { dataType: "a" | "b"; }>(template: T) => [T, any, any]
|
||||
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
|
||||
>dataType : "a" | "b"
|
||||
> : ^^^^^^^^^
|
||||
>template : T
|
||||
> : ^
|
||||
|
||||
declare function bar(template: { dataType: 'a' | 'b' }): [any, any, any];
|
||||
>bar : (template: { dataType: "a" | "b"; }) => [any, any, any]
|
||||
> : ^ ^^ ^^^^^
|
||||
>template : { dataType: "a" | "b"; }
|
||||
> : ^^^^^^^^^^^^ ^^^
|
||||
>dataType : "a" | "b"
|
||||
> : ^^^^^^^^^
|
||||
|
||||
// These should work without excess property errors - destructuring contexts
|
||||
const [, ,] = foo({ dataType: 'a', day: 0 });
|
||||
> : undefined
|
||||
> : ^^^^^^^^^
|
||||
> : undefined
|
||||
> : ^^^^^^^^^
|
||||
>foo({ dataType: 'a', day: 0 }) : [{ dataType: "a"; day: number; }, any, any]
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>foo : <T extends { dataType: "a" | "b"; }>(template: T) => [T, any, any]
|
||||
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
|
||||
>{ dataType: 'a', day: 0 } : { dataType: "a"; day: number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>dataType : "a"
|
||||
> : ^^^
|
||||
>'a' : "a"
|
||||
> : ^^^
|
||||
>day : number
|
||||
> : ^^^^^^
|
||||
>0 : 0
|
||||
> : ^
|
||||
|
||||
const [, , t] = foo({ dataType: 'a', day: 0 });
|
||||
> : undefined
|
||||
> : ^^^^^^^^^
|
||||
> : undefined
|
||||
> : ^^^^^^^^^
|
||||
>t : any
|
||||
> : ^^^
|
||||
>foo({ dataType: 'a', day: 0 }) : [{ dataType: "a" | "b"; }, any, any]
|
||||
> : ^^^^^^^^^^^^^ ^^^^^^^^^^^^^^
|
||||
>foo : <T extends { dataType: "a" | "b"; }>(template: T) => [T, any, any]
|
||||
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
|
||||
>{ dataType: 'a', day: 0 } : { dataType: "a"; day: number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>dataType : "a"
|
||||
> : ^^^
|
||||
>'a' : "a"
|
||||
> : ^^^
|
||||
>day : number
|
||||
> : ^^^^^^
|
||||
>0 : 0
|
||||
> : ^
|
||||
|
||||
const [x, y, z] = foo({ dataType: 'a', day: 0 });
|
||||
>x : { dataType: "a"; day: number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>y : any
|
||||
> : ^^^
|
||||
>z : any
|
||||
> : ^^^
|
||||
>foo({ dataType: 'a', day: 0 }) : [{ dataType: "a"; day: number; }, any, any]
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>foo : <T extends { dataType: "a" | "b"; }>(template: T) => [T, any, any]
|
||||
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
|
||||
>{ dataType: 'a', day: 0 } : { dataType: "a"; day: number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>dataType : "a"
|
||||
> : ^^^
|
||||
>'a' : "a"
|
||||
> : ^^^
|
||||
>day : number
|
||||
> : ^^^^^^
|
||||
>0 : 0
|
||||
> : ^
|
||||
|
||||
const [, ,] = bar({ dataType: 'a', day: 0 });
|
||||
> : undefined
|
||||
> : ^^^^^^^^^
|
||||
> : undefined
|
||||
> : ^^^^^^^^^
|
||||
>bar({ dataType: 'a', day: 0 }) : [any, any, any]
|
||||
> : ^^^^^^^^^^^^^^^
|
||||
>bar : (template: { dataType: "a" | "b"; }) => [any, any, any]
|
||||
> : ^ ^^ ^^^^^
|
||||
>{ dataType: 'a', day: 0 } : { dataType: "a"; day: number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>dataType : "a"
|
||||
> : ^^^
|
||||
>'a' : "a"
|
||||
> : ^^^
|
||||
>day : number
|
||||
> : ^^^^^^
|
||||
>0 : 0
|
||||
> : ^
|
||||
|
||||
const [, , u] = bar({ dataType: 'a', day: 0 });
|
||||
> : undefined
|
||||
> : ^^^^^^^^^
|
||||
> : undefined
|
||||
> : ^^^^^^^^^
|
||||
>u : any
|
||||
> : ^^^
|
||||
>bar({ dataType: 'a', day: 0 }) : [any, any, any]
|
||||
> : ^^^^^^^^^^^^^^^
|
||||
>bar : (template: { dataType: "a" | "b"; }) => [any, any, any]
|
||||
> : ^ ^^ ^^^^^
|
||||
>{ dataType: 'a', day: 0 } : { dataType: "a"; day: number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>dataType : "a"
|
||||
> : ^^^
|
||||
>'a' : "a"
|
||||
> : ^^^
|
||||
>day : number
|
||||
> : ^^^^^^
|
||||
>0 : 0
|
||||
> : ^
|
||||
|
||||
const [a, b, c] = bar({ dataType: 'a', day: 0 });
|
||||
>a : any
|
||||
> : ^^^
|
||||
>b : any
|
||||
> : ^^^
|
||||
>c : any
|
||||
> : ^^^
|
||||
>bar({ dataType: 'a', day: 0 }) : [any, any, any]
|
||||
> : ^^^^^^^^^^^^^^^
|
||||
>bar : (template: { dataType: "a" | "b"; }) => [any, any, any]
|
||||
> : ^ ^^ ^^^^^
|
||||
>{ dataType: 'a', day: 0 } : { dataType: "a"; day: number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>dataType : "a"
|
||||
> : ^^^
|
||||
>'a' : "a"
|
||||
> : ^^^
|
||||
>day : number
|
||||
> : ^^^^^^
|
||||
>0 : 0
|
||||
> : ^
|
||||
|
||||
// These should still report legitimate type errors
|
||||
const [, , invalid1] = foo({ dataType: 'invalid' });
|
||||
> : undefined
|
||||
> : ^^^^^^^^^
|
||||
> : undefined
|
||||
> : ^^^^^^^^^
|
||||
>invalid1 : any
|
||||
> : ^^^
|
||||
>foo({ dataType: 'invalid' }) : [{ dataType: "a" | "b"; }, any, any]
|
||||
> : ^^^^^^^^^^^^^ ^^^^^^^^^^^^^^
|
||||
>foo : <T extends { dataType: "a" | "b"; }>(template: T) => [T, any, any]
|
||||
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
|
||||
>{ dataType: 'invalid' } : { dataType: "invalid"; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>dataType : "invalid"
|
||||
> : ^^^^^^^^^
|
||||
>'invalid' : "invalid"
|
||||
> : ^^^^^^^^^
|
||||
|
||||
const [, , invalid2] = bar({ dataType: 'invalid' });
|
||||
> : undefined
|
||||
> : ^^^^^^^^^
|
||||
> : undefined
|
||||
> : ^^^^^^^^^
|
||||
>invalid2 : any
|
||||
> : ^^^
|
||||
>bar({ dataType: 'invalid' }) : [any, any, any]
|
||||
> : ^^^^^^^^^^^^^^^
|
||||
>bar : (template: { dataType: "a" | "b"; }) => [any, any, any]
|
||||
> : ^ ^^ ^^^^^
|
||||
>{ dataType: 'invalid' } : { dataType: "invalid"; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>dataType : "invalid"
|
||||
> : ^^^^^^^^^
|
||||
>'invalid' : "invalid"
|
||||
> : ^^^^^^^^^
|
||||
|
||||
// Non-destructuring cases - generic function should work, non-generic should error
|
||||
const result1 = foo({ dataType: 'a', day: 0 }); // OK - generic function
|
||||
>result1 : [{ dataType: "a"; day: number; }, any, any]
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>foo({ dataType: 'a', day: 0 }) : [{ dataType: "a"; day: number; }, any, any]
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>foo : <T extends { dataType: "a" | "b"; }>(template: T) => [T, any, any]
|
||||
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
|
||||
>{ dataType: 'a', day: 0 } : { dataType: "a"; day: number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>dataType : "a"
|
||||
> : ^^^
|
||||
>'a' : "a"
|
||||
> : ^^^
|
||||
>day : number
|
||||
> : ^^^^^^
|
||||
>0 : 0
|
||||
> : ^
|
||||
|
||||
const result2 = bar({ dataType: 'a', day: 0 }); // Error - non-generic with excess property
|
||||
>result2 : [any, any, any]
|
||||
> : ^^^^^^^^^^^^^^^
|
||||
>bar({ dataType: 'a', day: 0 }) : [any, any, any]
|
||||
> : ^^^^^^^^^^^^^^^
|
||||
>bar : (template: { dataType: "a" | "b"; }) => [any, any, any]
|
||||
> : ^ ^^ ^^^^^
|
||||
>{ dataType: 'a', day: 0 } : { dataType: "a"; day: number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>dataType : "a"
|
||||
> : ^^^
|
||||
>'a' : "a"
|
||||
> : ^^^
|
||||
>day : number
|
||||
> : ^^^^^^
|
||||
>0 : 0
|
||||
> : ^
|
||||
|
||||
// Assignment destructuring should also work
|
||||
let d, e, f: any;
|
||||
>d : any
|
||||
> : ^^^
|
||||
>e : any
|
||||
> : ^^^
|
||||
>f : any
|
||||
> : ^^^
|
||||
|
||||
[d, e, f] = foo({ dataType: 'a', day: 0 });
|
||||
>[d, e, f] = foo({ dataType: 'a', day: 0 }) : [{ dataType: "a"; day: number; }, any, any]
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>[d, e, f] : [any, any, any]
|
||||
> : ^^^^^^^^^^^^^^^
|
||||
>d : any
|
||||
> : ^^^
|
||||
>e : any
|
||||
> : ^^^
|
||||
>f : any
|
||||
> : ^^^
|
||||
>foo({ dataType: 'a', day: 0 }) : [{ dataType: "a"; day: number; }, any, any]
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>foo : <T extends { dataType: "a" | "b"; }>(template: T) => [T, any, any]
|
||||
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^
|
||||
>{ dataType: 'a', day: 0 } : { dataType: "a"; day: number; }
|
||||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
>dataType : "a"
|
||||
> : ^^^
|
||||
>'a' : "a"
|
||||
> : ^^^
|
||||
>day : number
|
||||
> : ^^^^^^
|
||||
>0 : 0
|
||||
> : ^
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
// @strict: true
|
||||
|
||||
declare function foo<T extends { dataType: 'a' | 'b' }>(template: T): [T, any, any];
|
||||
declare function bar(template: { dataType: 'a' | 'b' }): [any, any, any];
|
||||
|
||||
// These should work without excess property errors - destructuring contexts
|
||||
const [, ,] = foo({ dataType: 'a', day: 0 });
|
||||
const [, , t] = foo({ dataType: 'a', day: 0 });
|
||||
const [x, y, z] = foo({ dataType: 'a', day: 0 });
|
||||
|
||||
const [, ,] = bar({ dataType: 'a', day: 0 });
|
||||
const [, , u] = bar({ dataType: 'a', day: 0 });
|
||||
const [a, b, c] = bar({ dataType: 'a', day: 0 });
|
||||
|
||||
// These should still report legitimate type errors
|
||||
const [, , invalid1] = foo({ dataType: 'invalid' });
|
||||
const [, , invalid2] = bar({ dataType: 'invalid' });
|
||||
|
||||
// Non-destructuring cases - generic function should work, non-generic should error
|
||||
const result1 = foo({ dataType: 'a', day: 0 }); // OK - generic function
|
||||
const result2 = bar({ dataType: 'a', day: 0 }); // Error - non-generic with excess property
|
||||
|
||||
// Assignment destructuring should also work
|
||||
let d, e, f: any;
|
||||
[d, e, f] = foo({ dataType: 'a', day: 0 });
|
||||
Reference in New Issue
Block a user