Skip to content

Pad object literal types with implicit anys based on binding pattern elements #59924

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 52 additions & 24 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11931,6 +11931,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (isBindingPattern(element.name)) {
return getTypeFromBindingPattern(element.name, includePatternInType, reportErrors);
}
if (isBindingPattern(element.parent)) {
const contextualType = getContextualPaddingType(element);
if (contextualType) {
return contextualType;
}
}
if (reportErrors && !declarationBelongsToPrivateAmbientMember(element)) {
reportImplicitAny(element, anyType);
}
Expand All @@ -11947,23 +11953,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
let stringIndexInfo: IndexInfo | undefined;
let objectFlags = ObjectFlags.ObjectLiteral | ObjectFlags.ContainsObjectOrArrayLiteral;
forEach(pattern.elements, e => {
const name = e.propertyName || e.name as Identifier;
if (e.dotDotDotToken) {
stringIndexInfo = createIndexInfo(stringType, anyType, /*isReadonly*/ false);
return;
}

const exprType = getLiteralTypeFromPropertyName(name);
if (!isTypeUsableAsPropertyName(exprType)) {
const name = getPropertyNameFromBindingElement(e);
if (!name) {
// do not include computed properties in the implied type
objectFlags |= ObjectFlags.ObjectLiteralPatternWithComputedProperties;
return;
}
const text = getPropertyNameFromType(exprType);
const flags = SymbolFlags.Property | (e.initializer ? SymbolFlags.Optional : 0);
const symbol = createSymbol(flags, text);
const contextualType = !includePatternInType && isBindingPattern(e.parent) ? getContextualPaddingType(e.parent) : undefined;
const paddingSymbol = contextualType && getPropertyOfType(contextualType, name);
const flags = SymbolFlags.Property | (e.initializer || !includePatternInType && (!paddingSymbol || paddingSymbol.flags & SymbolFlags.Optional) ? SymbolFlags.Optional : 0);
const symbol = createSymbol(flags, name);
symbol.links.type = getTypeFromBindingElement(e, includePatternInType, reportErrors);
symbol.links.bindingElement = e;
members.set(symbol.escapedName, symbol);
});
const result = createAnonymousType(/*symbol*/ undefined, members, emptyArray, emptyArray, stringIndexInfo ? [stringIndexInfo] : emptyArray);
Expand Down Expand Up @@ -31342,11 +31346,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (index < 0) return undefined;
return getContextualTypeForElementExpression(parentType, index);
}
const nameType = getLiteralTypeFromPropertyName(name);
if (isTypeUsableAsPropertyName(nameType)) {
const text = getPropertyNameFromType(nameType);
return getTypeOfPropertyOfType(parentType, text);
}
const propertyName = getPropertyNameFromBindingElement(declaration);
return propertyName && getTypeOfPropertyOfType(parentType, propertyName);
}

function getContextualTypeForStaticPropertyDeclaration(declaration: PropertyDeclaration, contextFlags: ContextFlags | undefined): Type | undefined {
Expand Down Expand Up @@ -32208,11 +32209,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return undefined;
}

function getContextualPaddingType(node: BindingPattern | BindingElement): Type | undefined {
const index = findContextualNode(node, /*includeCaches*/ true);
if (index >= 0) {
return contextualTypes[index];
}
const { parent } = node;
switch (parent.kind) {
case SyntaxKind.ObjectBindingPattern: {
const type = getContextualPaddingType(parent);
const name = type && getPropertyNameFromBindingElement(node as BindingElement);
return name ? getTypeOfPropertyOfType(type, name) : undefined;
}
case SyntaxKind.BindingElement: {
if (parent.parent.kind === SyntaxKind.ArrayBindingPattern) {
break;
}
const type = getContextualPaddingType(parent.parent);
const name = type && getPropertyNameFromBindingElement(parent);
return name ? getTypeOfPropertyOfType(type, name) : undefined;
}
}
return undefined;
}

function pushCachedContextualType(node: Expression) {
pushContextualType(node, getContextualType(node, /*contextFlags*/ undefined), /*isCache*/ true);
}

function pushContextualType(node: Expression, type: Type | undefined, isCache: boolean) {
function pushContextualType(node: Node, type: Type | undefined, isCache: boolean) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be a narrower type than just Node?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this implementation, it could be Expression | BindingPattern | BindingElement if you'd prefer that.

2 extra notes that come to my mind now:

  • maybe I shouldn't be reusing the same contextualTypes stack for this and I should just introduce a new one? It seemed fine here to avoid creating a new but then reusing getContextualType wasn't possible so it's slightly weird now that I'm only using part of the existing pattern . Perhaps with a new context flag it would be possible but introducing getContextualPaddingType seemed easier
  • if this gets approved, it might be a good idea to explore expanding getContextualPaddingType with support for array patterns and using pushContextualType/popContextualType in padTupleType. Since this PR tries to address a regression in a backportable manner I refrained from doing this to avoid any new unforeseen behavioral changes

contextualTypeNodes[contextualTypeCount] = node;
contextualTypes[contextualTypeCount] = type;
contextualIsCache[contextualTypeCount] = isCache;
Expand Down Expand Up @@ -40563,27 +40588,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}

function padObjectLiteralType(type: ObjectType, pattern: ObjectBindingPattern): Type {
let missingElements: BindingElement[] | undefined;
let paddableElements: BindingElement[] | undefined;
for (const e of pattern.elements) {
if (e.initializer) {
const name = getPropertyNameFromBindingElement(e);
if (name && !getPropertyOfType(type, name)) {
missingElements = append(missingElements, e);
}
const name = getPropertyNameFromBindingElement(e);
if (name && (!getPropertyOfType(type, name) || isBindingPattern(e.name))) {
paddableElements = append(paddableElements, e);
}
}
if (!missingElements) {
if (!paddableElements) {
return type;
}
const members = createSymbolTable();
for (const prop of getPropertiesOfObjectType(type)) {
members.set(prop.escapedName, prop);
}
for (const e of missingElements) {
const symbol = createSymbol(SymbolFlags.Property | SymbolFlags.Optional, getPropertyNameFromBindingElement(e)!);
symbol.links.type = getTypeFromBindingElement(e, /*includePatternInType*/ false, /*reportErrors*/ false);
pushContextualType(pattern, type, /*isCache*/ true);
for (const e of paddableElements) {
const name = getPropertyNameFromBindingElement(e)!;
const paddingSymbol = getPropertyOfType(type, name);
const isOptional = e.initializer && !paddingSymbol || !members.has(name) || paddingSymbol && (paddingSymbol.flags & SymbolFlags.Optional);
const symbol = createSymbol(SymbolFlags.Property | (isOptional || !members.has(name) ? SymbolFlags.Optional : 0), name);
symbol.links.type = getTypeFromBindingElement(e, /*includePatternInType*/ false, /*reportErrors*/ true);
members.set(symbol.escapedName, symbol);
}
popContextualType();
const result = createAnonymousType(type.symbol, members, emptyArray, emptyArray, getIndexInfosOfType(type));
result.objectFlags = type.objectFlags;
return result;
Expand Down
1 change: 0 additions & 1 deletion src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6010,7 +6010,6 @@ export interface SymbolLinks {
exportsChecked?: boolean; // True if exports of external module have been checked
typeParametersChecked?: boolean; // True if type parameters of merged class and interface declarations have been checked.
isDeclarationWithCollidingName?: boolean; // True if symbol is block scoped redeclaration
bindingElement?: BindingElement; // Binding element associated with property symbol
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one has been introduced in #4598 but its usage was removed in #59183

originatingImport?: ImportDeclaration | ImportCall; // Import declaration which produced the symbol, present if the symbol is marked as uncallable but had call signatures in `resolveESModuleSymbol`
lateSymbol?: Symbol; // Late-bound symbol for a computed property
specifierCache?: Map<ModeAwareCacheKey, string>; // For symbols corresponding to external modules, a cache of incoming path -> module specifier name mappings
Expand Down
1 change: 0 additions & 1 deletion src/compiler/utilitiesPublic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2550,7 +2550,6 @@ export function hasInitializer(node: Node): node is HasInitializer {
return !!(node as HasInitializer).initializer;
}

/** True if has initializer node attached to it. */
export function hasOnlyExpressionInitializer(node: Node): node is HasExpressionInitializer {
switch (node.kind) {
case SyntaxKind.VariableDeclaration:
Expand Down
1 change: 0 additions & 1 deletion tests/baselines/reference/api/typescript.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8750,7 +8750,6 @@ declare namespace ts {
function isJSDocCommentContainingNode(node: Node): boolean;
function isSetAccessor(node: Node): node is SetAccessorDeclaration;
function isGetAccessor(node: Node): node is GetAccessorDeclaration;
/** True if has initializer node attached to it. */
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this one was copied over from an internal function declared above it, I don't think this comment is true as it made much more sense for the other function

function hasOnlyExpressionInitializer(node: Node): node is HasExpressionInitializer;
function isObjectLiteralElement(node: Node): node is ObjectLiteralElement;
function isStringLiteralLike(node: Node | FileReference): node is StringLiteralLike;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ argumentExpressionContextualTyping.ts(16,5): error TS2345: Argument of type '(st
Target requires 3 element(s) but source may have fewer.
argumentExpressionContextualTyping.ts(17,5): error TS2345: Argument of type '[string, number, true, ...(string | number | boolean)[]]' is not assignable to parameter of type '[string, number, boolean]'.
Target allows only 3 element(s) but source may have more.
argumentExpressionContextualTyping.ts(18,5): error TS2345: Argument of type '{ x: (string | number)[]; y: { c: boolean; d: string; e: number; }; }' is not assignable to parameter of type '{ x: [any, any]; y: { c: any; d: any; e: any; }; }'.
argumentExpressionContextualTyping.ts(18,5): error TS2345: Argument of type '{ x: (string | number)[]; y: { c: boolean; d: string; e: number; }; }' is not assignable to parameter of type '{ x?: [any, any]; y?: { c?: any; d?: any; e?: any; }; }'.
Types of property 'x' are incompatible.
Type '(string | number)[]' is not assignable to type '[any, any]'.
Target requires 2 element(s) but source may have fewer.
Expand Down Expand Up @@ -34,7 +34,7 @@ argumentExpressionContextualTyping.ts(18,5): error TS2345: Argument of type '{ x
!!! error TS2345: Target allows only 3 element(s) but source may have more.
foo(o); // Error because x has an array type namely (string|number)[]
~
!!! error TS2345: Argument of type '{ x: (string | number)[]; y: { c: boolean; d: string; e: number; }; }' is not assignable to parameter of type '{ x: [any, any]; y: { c: any; d: any; e: any; }; }'.
!!! error TS2345: Argument of type '{ x: (string | number)[]; y: { c: boolean; d: string; e: number; }; }' is not assignable to parameter of type '{ x?: [any, any]; y?: { c?: any; d?: any; e?: any; }; }'.
!!! error TS2345: Types of property 'x' are incompatible.
!!! error TS2345: Type '(string | number)[]' is not assignable to type '[any, any]'.
!!! error TS2345: Target requires 2 element(s) but source may have fewer.
20 changes: 10 additions & 10 deletions tests/baselines/reference/argumentExpressionContextualTyping.types
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
=== argumentExpressionContextualTyping.ts ===
// In a typed function call, argument expressions are contextually typed by their corresponding parameter types.
function foo({x: [a, b], y: {c, d, e}}) { }
>foo : ({ x: [a, b], y: { c, d, e } }: { x: [any, any]; y: { c: any; d: any; e: any; }; }) => void
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>foo : ({ x: [a, b], y: { c, d, e } }: { x?: [any, any]; y?: { c?: any; d?: any; e?: any; }; }) => void
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>x : any
> : ^^^
>a : any
Expand All @@ -21,8 +21,8 @@ function foo({x: [a, b], y: {c, d, e}}) { }
> : ^^^

function bar({x: [a, b = 10], y: {c, d, e = { f:1 }}}) { }
>bar : ({ x: [a, b], y: { c, d, e } }: { x: [any, number?]; y: { c: any; d: any; e?: { f: number; }; }; }) => void
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>bar : ({ x: [a, b], y: { c, d, e } }: { x?: [any, number?]; y?: { c?: any; d?: any; e?: { f: number; }; }; }) => void
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>x : any
> : ^^^
>a : any
Expand Down Expand Up @@ -125,16 +125,16 @@ var o1: { x: [string, number], y: { c: boolean, d: string, e: number } } = { x:
foo(o1); // Not error since x has contextual type of tuple namely [string, number]
>foo(o1) : void
> : ^^^^
>foo : ({ x: [a, b], y: { c, d, e } }: { x: [any, any]; y: { c: any; d: any; e: any; }; }) => void
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>foo : ({ x: [a, b], y: { c, d, e } }: { x?: [any, any]; y?: { c?: any; d?: any; e?: any; }; }) => void
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>o1 : { x: [string, number]; y: { c: boolean; d: string; e: number; }; }
> : ^^^^^ ^^^^^ ^^^

foo({ x: ["string", 1], y: { c: true, d: "world", e: 3 } }); // Not error
>foo({ x: ["string", 1], y: { c: true, d: "world", e: 3 } }) : void
> : ^^^^
>foo : ({ x: [a, b], y: { c, d, e } }: { x: [any, any]; y: { c: any; d: any; e: any; }; }) => void
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>foo : ({ x: [a, b], y: { c, d, e } }: { x?: [any, any]; y?: { c?: any; d?: any; e?: any; }; }) => void
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>{ x: ["string", 1], y: { c: true, d: "world", e: 3 } } : { x: [string, number]; y: { c: boolean; d: string; e: number; }; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>x : [string, number]
Expand Down Expand Up @@ -237,8 +237,8 @@ baz(["string", 1, true, ...array]); // Error
foo(o); // Error because x has an array type namely (string|number)[]
>foo(o) : void
> : ^^^^
>foo : ({ x: [a, b], y: { c, d, e } }: { x: [any, any]; y: { c: any; d: any; e: any; }; }) => void
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>foo : ({ x: [a, b], y: { c, d, e } }: { x?: [any, any]; y?: { c?: any; d?: any; e?: any; }; }) => void
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>o : { x: (string | number)[]; y: { c: boolean; d: string; e: number; }; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

=== arityErrorRelatedSpanBindingPattern.ts ===
function foo(a, b, {c}): void {}
>foo : (a: any, b: any, { c }: { c: any; }) => void
> : ^ ^^^^^^^ ^^^^^^^ ^^^^^^^^^^^^^^^^^^
>foo : (a: any, b: any, { c }: { c?: any; }) => void
> : ^ ^^^^^^^ ^^^^^^^ ^^^^^^^^^^^^^^^^^^^
>a : any
> : ^^^
>b : any
Expand All @@ -24,8 +24,8 @@ function bar(a, b, [c]): void {}
foo("", 0);
>foo("", 0) : void
> : ^^^^
>foo : (a: any, b: any, { c }: { c: any; }) => void
> : ^ ^^^^^^^ ^^^^^^^ ^^^^^^^^^^^^^^^^^^
>foo : (a: any, b: any, { c }: { c?: any; }) => void
> : ^ ^^^^^^^ ^^^^^^^ ^^^^^^^^^^^^^^^^^^^
>"" : ""
> : ^^
>0 : 0
Expand Down
24 changes: 12 additions & 12 deletions tests/baselines/reference/arrowFunctionExpressions.types
Original file line number Diff line number Diff line change
Expand Up @@ -129,18 +129,18 @@ var p5 = ([a = 1]) => { };
> : ^

var p6 = ({ a }) => { };
>p6 : ({ a }: { a: any; }) => void
> : ^ ^^^^^^^^^^^^^^^^^^^^^^
>({ a }) => { } : ({ a }: { a: any; }) => void
> : ^ ^^^^^^^^^^^^^^^^^^^^^^
>p6 : ({ a }: { a?: any; }) => void
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^
>({ a }) => { } : ({ a }: { a?: any; }) => void
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^
>a : any
> : ^^^

var p7 = ({ a: { b } }) => { };
>p7 : ({ a: { b } }: { a: { b: any; }; }) => void
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>({ a: { b } }) => { } : ({ a: { b } }: { a: { b: any; }; }) => void
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>p7 : ({ a: { b } }: { a?: { b?: any; }; }) => void
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>({ a: { b } }) => { } : ({ a: { b } }: { a?: { b?: any; }; }) => void
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>a : any
> : ^^^
>b : any
Expand Down Expand Up @@ -175,10 +175,10 @@ var p9 = ({ a: { b = 1 } = { b: 1 } }) => { };
> : ^

var p10 = ([{ value, done }]) => { };
>p10 : ([{ value, done }]: [{ value: any; done: any; }]) => void
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>([{ value, done }]) => { } : ([{ value, done }]: [{ value: any; done: any; }]) => void
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>p10 : ([{ value, done }]: [{ value?: any; done?: any; }]) => void
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>([{ value, done }]) => { } : ([{ value, done }]: [{ value?: any; done?: any; }]) => void
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>value : any
> : ^^^
>done : any
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
// https://github.com/Microsoft/TypeScript/issues/19187

async ({ foo, bar, ...rest }) => bar(await foo);
>async ({ foo, bar, ...rest }) => bar(await foo) : ({ foo, bar, ...rest }: { [x: string]: any; foo: any; bar: any; }) => Promise<any>
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>async ({ foo, bar, ...rest }) => bar(await foo) : ({ foo, bar, ...rest }: { [x: string]: any; foo?: any; bar?: any; }) => Promise<any>
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>foo : any
> : ^^^
>bar : any
Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/asyncWithVarShadowing_es6.types
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,8 @@ async function fn17(x) {
}

async function fn18({ x }) {
>fn18 : ({ x }: { x: any; }) => Promise<void>
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>fn18 : ({ x }: { x?: any; }) => Promise<void>
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>x : any
> : ^^^

Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/commentsAfterSpread.types
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,8 @@ const j = (
> : ^^^^^^

function k ({
>k : ({ first, ...rest }: { [x: string]: any; first: any; }) => { [x: string]: any; }
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>k : ({ first, ...rest }: { [x: string]: any; first?: any; }) => { [x: string]: any; }
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

first,
>first : any
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

=== computerPropertiesInES5ShouldBeTransformed.ts ===
const b = ({ [`key`]: renamed }) => renamed;
>b : ({ [`key`]: renamed }: { key: any; }) => any
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^
>({ [`key`]: renamed }) => renamed : ({ [`key`]: renamed }: { key: any; }) => any
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^
>b : ({ [`key`]: renamed }: { key?: any; }) => any
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^
>({ [`key`]: renamed }) => renamed : ({ [`key`]: renamed }: { key?: any; }) => any
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^
>`key` : "key"
> : ^^^^^
>renamed : any
Expand Down
Loading