diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 073c0d46d7b4e..21d572e7b7478 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -23515,9 +23515,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const baseObjectType = getBaseConstraintOfType(objectType) || objectType; const baseIndexType = getBaseConstraintOfType(indexType) || indexType; if (!isGenericObjectType(baseObjectType) && !isGenericIndexType(baseIndexType)) { - const accessFlags = AccessFlags.Writing | (baseObjectType !== objectType ? AccessFlags.NoIndexSignatures : 0); - const constraint = getIndexedAccessTypeOrUndefined(baseObjectType, baseIndexType, accessFlags); - if (constraint) { + let constraint; + if ( + isMappedTypeGenericIndexedAccess(target) && + (constraint = getBaseConstraintOfType(target)) && + (result = isRelatedTo(source, constraint, RecursionFlags.Target, /*reportErrors*/ false, /*headMessage*/ undefined, intersectionState)) + ) { + return result; + } + if (constraint = getIndexedAccessTypeOrUndefined(baseObjectType, baseIndexType, AccessFlags.Writing | (baseObjectType !== objectType ? AccessFlags.NoIndexSignatures : 0))) { if (reportErrors && originalErrorInfo) { // create a new chain for the constraint error resetErrorInfo(saveErrorInfo); diff --git a/tests/baselines/reference/correlatedUnions2.symbols b/tests/baselines/reference/correlatedUnions2.symbols new file mode 100644 index 0000000000000..78709a660318e --- /dev/null +++ b/tests/baselines/reference/correlatedUnions2.symbols @@ -0,0 +1,93 @@ +//// [tests/cases/compiler/correlatedUnions2.ts] //// + +=== correlatedUnions2.ts === +// https://github.com/microsoft/TypeScript/issues/61676 + +type Definitions = { +>Definitions : Symbol(Definitions, Decl(correlatedUnions2.ts, 0, 0)) + + onFoo: [arg: number]; +>onFoo : Symbol(onFoo, Decl(correlatedUnions2.ts, 2, 20)) + + onBar: [arg: string]; +>onBar : Symbol(onBar, Decl(correlatedUnions2.ts, 3, 23)) + +}; + +type SomeCallbacks = { +>SomeCallbacks : Symbol(SomeCallbacks, Decl(correlatedUnions2.ts, 5, 2)) + + [K in keyof Definitions]: (...args: Definitions[K]) => void; +>K : Symbol(K, Decl(correlatedUnions2.ts, 8, 3)) +>Definitions : Symbol(Definitions, Decl(correlatedUnions2.ts, 0, 0)) +>args : Symbol(args, Decl(correlatedUnions2.ts, 8, 29)) +>Definitions : Symbol(Definitions, Decl(correlatedUnions2.ts, 0, 0)) +>K : Symbol(K, Decl(correlatedUnions2.ts, 8, 3)) + +}; + +const wrapCallback = ( +>wrapCallback : Symbol(wrapCallback, Decl(correlatedUnions2.ts, 11, 5)) +>K : Symbol(K, Decl(correlatedUnions2.ts, 11, 22)) +>SomeCallbacks : Symbol(SomeCallbacks, Decl(correlatedUnions2.ts, 5, 2)) + + source: SomeCallbacks, +>source : Symbol(source, Decl(correlatedUnions2.ts, 11, 53)) +>SomeCallbacks : Symbol(SomeCallbacks, Decl(correlatedUnions2.ts, 5, 2)) + + target: SomeCallbacks, +>target : Symbol(target, Decl(correlatedUnions2.ts, 12, 24)) +>SomeCallbacks : Symbol(SomeCallbacks, Decl(correlatedUnions2.ts, 5, 2)) + + key: K, +>key : Symbol(key, Decl(correlatedUnions2.ts, 13, 24)) +>K : Symbol(K, Decl(correlatedUnions2.ts, 11, 22)) + +) => { + const callback = source[key]; +>callback : Symbol(callback, Decl(correlatedUnions2.ts, 16, 7)) +>source : Symbol(source, Decl(correlatedUnions2.ts, 11, 53)) +>key : Symbol(key, Decl(correlatedUnions2.ts, 13, 24)) + + target[key] = (...args) => { +>target : Symbol(target, Decl(correlatedUnions2.ts, 12, 24)) +>key : Symbol(key, Decl(correlatedUnions2.ts, 13, 24)) +>args : Symbol(args, Decl(correlatedUnions2.ts, 18, 17)) + + if (Math.random() > 0.5) { +>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 callback(...args); +>callback : Symbol(callback, Decl(correlatedUnions2.ts, 16, 7)) +>args : Symbol(args, Decl(correlatedUnions2.ts, 18, 17)) + } + }; +}; + +function wrapAll(callbacks: SomeCallbacks): SomeCallbacks { +>wrapAll : Symbol(wrapAll, Decl(correlatedUnions2.ts, 23, 2)) +>callbacks : Symbol(callbacks, Decl(correlatedUnions2.ts, 25, 17)) +>SomeCallbacks : Symbol(SomeCallbacks, Decl(correlatedUnions2.ts, 5, 2)) +>SomeCallbacks : Symbol(SomeCallbacks, Decl(correlatedUnions2.ts, 5, 2)) + + const wrapped = {} as SomeCallbacks; +>wrapped : Symbol(wrapped, Decl(correlatedUnions2.ts, 26, 7)) +>SomeCallbacks : Symbol(SomeCallbacks, Decl(correlatedUnions2.ts, 5, 2)) + + for (let key in callbacks) { +>key : Symbol(key, Decl(correlatedUnions2.ts, 27, 10)) +>callbacks : Symbol(callbacks, Decl(correlatedUnions2.ts, 25, 17)) + + wrapCallback(callbacks, wrapped, key as keyof SomeCallbacks); +>wrapCallback : Symbol(wrapCallback, Decl(correlatedUnions2.ts, 11, 5)) +>callbacks : Symbol(callbacks, Decl(correlatedUnions2.ts, 25, 17)) +>wrapped : Symbol(wrapped, Decl(correlatedUnions2.ts, 26, 7)) +>key : Symbol(key, Decl(correlatedUnions2.ts, 27, 10)) +>SomeCallbacks : Symbol(SomeCallbacks, Decl(correlatedUnions2.ts, 5, 2)) + } + return wrapped; +>wrapped : Symbol(wrapped, Decl(correlatedUnions2.ts, 26, 7)) +} + diff --git a/tests/baselines/reference/correlatedUnions2.types b/tests/baselines/reference/correlatedUnions2.types new file mode 100644 index 0000000000000..5871ebbd40e1e --- /dev/null +++ b/tests/baselines/reference/correlatedUnions2.types @@ -0,0 +1,138 @@ +//// [tests/cases/compiler/correlatedUnions2.ts] //// + +=== correlatedUnions2.ts === +// https://github.com/microsoft/TypeScript/issues/61676 + +type Definitions = { +>Definitions : Definitions +> : ^^^^^^^^^^^ + + onFoo: [arg: number]; +>onFoo : [arg: number] +> : ^^^^^^^^^^^^^ + + onBar: [arg: string]; +>onBar : [arg: string] +> : ^^^^^^^^^^^^^ + +}; + +type SomeCallbacks = { +>SomeCallbacks : SomeCallbacks +> : ^^^^^^^^^^^^^ + + [K in keyof Definitions]: (...args: Definitions[K]) => void; +>args : Definitions[K] +> : ^^^^^^^^^^^^^^ + +}; + +const wrapCallback = ( +>wrapCallback : (source: SomeCallbacks, target: SomeCallbacks, key: K) => void +> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^^^^^ +>( source: SomeCallbacks, target: SomeCallbacks, key: K,) => { const callback = source[key]; target[key] = (...args) => { if (Math.random() > 0.5) { return callback(...args); } };} : (source: SomeCallbacks, target: SomeCallbacks, key: K) => void +> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^^^^^ + + source: SomeCallbacks, +>source : SomeCallbacks +> : ^^^^^^^^^^^^^ + + target: SomeCallbacks, +>target : SomeCallbacks +> : ^^^^^^^^^^^^^ + + key: K, +>key : K +> : ^ + +) => { + const callback = source[key]; +>callback : SomeCallbacks[K] +> : ^^^^^^^^^^^^^^^^ +>source[key] : SomeCallbacks[K] +> : ^^^^^^^^^^^^^^^^ +>source : SomeCallbacks +> : ^^^^^^^^^^^^^ +>key : K +> : ^ + + target[key] = (...args) => { +>target[key] = (...args) => { if (Math.random() > 0.5) { return callback(...args); } } : (...args: Definitions[K]) => void +> : ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ +>target[key] : SomeCallbacks[K] +> : ^^^^^^^^^^^^^^^^ +>target : SomeCallbacks +> : ^^^^^^^^^^^^^ +>key : K +> : ^ +>(...args) => { if (Math.random() > 0.5) { return callback(...args); } } : (...args: Definitions[K]) => void +> : ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ +>args : Definitions[K] +> : ^^^^^^^^^^^^^^ + + if (Math.random() > 0.5) { +>Math.random() > 0.5 : boolean +> : ^^^^^^^ +>Math.random() : number +> : ^^^^^^ +>Math.random : () => number +> : ^^^^^^ +>Math : Math +> : ^^^^ +>random : () => number +> : ^^^^^^ +>0.5 : 0.5 +> : ^^^ + + return callback(...args); +>callback(...args) : void +> : ^^^^ +>callback : SomeCallbacks[K] +> : ^^^^^^^^^^^^^^^^ +>...args : string | number +> : ^^^^^^^^^^^^^^^ +>args : Definitions[K] +> : ^^^^^^^^^^^^^^ + } + }; +}; + +function wrapAll(callbacks: SomeCallbacks): SomeCallbacks { +>wrapAll : (callbacks: SomeCallbacks) => SomeCallbacks +> : ^ ^^ ^^^^^ +>callbacks : SomeCallbacks +> : ^^^^^^^^^^^^^ + + const wrapped = {} as SomeCallbacks; +>wrapped : SomeCallbacks +> : ^^^^^^^^^^^^^ +>{} as SomeCallbacks : SomeCallbacks +> : ^^^^^^^^^^^^^ +>{} : {} +> : ^^ + + for (let key in callbacks) { +>key : string +> : ^^^^^^ +>callbacks : SomeCallbacks +> : ^^^^^^^^^^^^^ + + wrapCallback(callbacks, wrapped, key as keyof SomeCallbacks); +>wrapCallback(callbacks, wrapped, key as keyof SomeCallbacks) : void +> : ^^^^ +>wrapCallback : (source: SomeCallbacks, target: SomeCallbacks, key: K) => void +> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^^^^^ +>callbacks : SomeCallbacks +> : ^^^^^^^^^^^^^ +>wrapped : SomeCallbacks +> : ^^^^^^^^^^^^^ +>key as keyof SomeCallbacks : keyof Definitions +> : ^^^^^^^^^^^^^^^^^ +>key : string +> : ^^^^^^ + } + return wrapped; +>wrapped : SomeCallbacks +> : ^^^^^^^^^^^^^ +} + diff --git a/tests/baselines/reference/correlatedUnions3.symbols b/tests/baselines/reference/correlatedUnions3.symbols new file mode 100644 index 0000000000000..28c4e4790e722 --- /dev/null +++ b/tests/baselines/reference/correlatedUnions3.symbols @@ -0,0 +1,96 @@ +//// [tests/cases/compiler/correlatedUnions3.ts] //// + +=== correlatedUnions3.ts === +type Definitions = { +>Definitions : Symbol(Definitions, Decl(correlatedUnions3.ts, 0, 0)) + + onFoo: [arg: number]; +>onFoo : Symbol(onFoo, Decl(correlatedUnions3.ts, 0, 20)) + + onBar: [arg: string]; +>onBar : Symbol(onBar, Decl(correlatedUnions3.ts, 1, 23)) + +}; + +type SomeCallbacks = { +>SomeCallbacks : Symbol(SomeCallbacks, Decl(correlatedUnions3.ts, 3, 2)) + + [K in keyof Definitions]?: (...args: Definitions[K]) => void; +>K : Symbol(K, Decl(correlatedUnions3.ts, 6, 3)) +>Definitions : Symbol(Definitions, Decl(correlatedUnions3.ts, 0, 0)) +>args : Symbol(args, Decl(correlatedUnions3.ts, 6, 30)) +>Definitions : Symbol(Definitions, Decl(correlatedUnions3.ts, 0, 0)) +>K : Symbol(K, Decl(correlatedUnions3.ts, 6, 3)) + +}; + +const wrapCallback = ( +>wrapCallback : Symbol(wrapCallback, Decl(correlatedUnions3.ts, 9, 5)) +>K : Symbol(K, Decl(correlatedUnions3.ts, 9, 22)) +>SomeCallbacks : Symbol(SomeCallbacks, Decl(correlatedUnions3.ts, 3, 2)) + + source: SomeCallbacks, +>source : Symbol(source, Decl(correlatedUnions3.ts, 9, 53)) +>SomeCallbacks : Symbol(SomeCallbacks, Decl(correlatedUnions3.ts, 3, 2)) + + target: SomeCallbacks, +>target : Symbol(target, Decl(correlatedUnions3.ts, 10, 24)) +>SomeCallbacks : Symbol(SomeCallbacks, Decl(correlatedUnions3.ts, 3, 2)) + + key: K, +>key : Symbol(key, Decl(correlatedUnions3.ts, 11, 24)) +>K : Symbol(K, Decl(correlatedUnions3.ts, 9, 22)) + +) => { + const callback = source[key]; +>callback : Symbol(callback, Decl(correlatedUnions3.ts, 14, 7)) +>source : Symbol(source, Decl(correlatedUnions3.ts, 9, 53)) +>key : Symbol(key, Decl(correlatedUnions3.ts, 11, 24)) + + target[key] = +>target : Symbol(target, Decl(correlatedUnions3.ts, 10, 24)) +>key : Symbol(key, Decl(correlatedUnions3.ts, 11, 24)) + + callback && +>callback : Symbol(callback, Decl(correlatedUnions3.ts, 14, 7)) + + ((...args) => { +>args : Symbol(args, Decl(correlatedUnions3.ts, 17, 6)) + + if (Math.random() > 0.5) { +>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 callback(...args); +>callback : Symbol(callback, Decl(correlatedUnions3.ts, 14, 7)) +>args : Symbol(args, Decl(correlatedUnions3.ts, 17, 6)) + } + }); +}; + +function wrapAll(callbacks: SomeCallbacks): SomeCallbacks { +>wrapAll : Symbol(wrapAll, Decl(correlatedUnions3.ts, 22, 2)) +>callbacks : Symbol(callbacks, Decl(correlatedUnions3.ts, 24, 17)) +>SomeCallbacks : Symbol(SomeCallbacks, Decl(correlatedUnions3.ts, 3, 2)) +>SomeCallbacks : Symbol(SomeCallbacks, Decl(correlatedUnions3.ts, 3, 2)) + + const wrapped: SomeCallbacks = {}; +>wrapped : Symbol(wrapped, Decl(correlatedUnions3.ts, 25, 7)) +>SomeCallbacks : Symbol(SomeCallbacks, Decl(correlatedUnions3.ts, 3, 2)) + + for (let key in callbacks) { +>key : Symbol(key, Decl(correlatedUnions3.ts, 26, 10)) +>callbacks : Symbol(callbacks, Decl(correlatedUnions3.ts, 24, 17)) + + wrapCallback(callbacks, wrapped, key as keyof SomeCallbacks); +>wrapCallback : Symbol(wrapCallback, Decl(correlatedUnions3.ts, 9, 5)) +>callbacks : Symbol(callbacks, Decl(correlatedUnions3.ts, 24, 17)) +>wrapped : Symbol(wrapped, Decl(correlatedUnions3.ts, 25, 7)) +>key : Symbol(key, Decl(correlatedUnions3.ts, 26, 10)) +>SomeCallbacks : Symbol(SomeCallbacks, Decl(correlatedUnions3.ts, 3, 2)) + } + return wrapped; +>wrapped : Symbol(wrapped, Decl(correlatedUnions3.ts, 25, 7)) +} + diff --git a/tests/baselines/reference/correlatedUnions3.types b/tests/baselines/reference/correlatedUnions3.types new file mode 100644 index 0000000000000..1cfd825994527 --- /dev/null +++ b/tests/baselines/reference/correlatedUnions3.types @@ -0,0 +1,144 @@ +//// [tests/cases/compiler/correlatedUnions3.ts] //// + +=== correlatedUnions3.ts === +type Definitions = { +>Definitions : Definitions +> : ^^^^^^^^^^^ + + onFoo: [arg: number]; +>onFoo : [arg: number] +> : ^^^^^^^^^^^^^ + + onBar: [arg: string]; +>onBar : [arg: string] +> : ^^^^^^^^^^^^^ + +}; + +type SomeCallbacks = { +>SomeCallbacks : SomeCallbacks +> : ^^^^^^^^^^^^^ + + [K in keyof Definitions]?: (...args: Definitions[K]) => void; +>args : Definitions[K] +> : ^^^^^^^^^^^^^^ + +}; + +const wrapCallback = ( +>wrapCallback : (source: SomeCallbacks, target: SomeCallbacks, key: K) => void +> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^^^^^ +>( source: SomeCallbacks, target: SomeCallbacks, key: K,) => { const callback = source[key]; target[key] = callback && ((...args) => { if (Math.random() > 0.5) { return callback(...args); } });} : (source: SomeCallbacks, target: SomeCallbacks, key: K) => void +> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^^^^^ + + source: SomeCallbacks, +>source : SomeCallbacks +> : ^^^^^^^^^^^^^ + + target: SomeCallbacks, +>target : SomeCallbacks +> : ^^^^^^^^^^^^^ + + key: K, +>key : K +> : ^ + +) => { + const callback = source[key]; +>callback : SomeCallbacks[K] +> : ^^^^^^^^^^^^^^^^ +>source[key] : SomeCallbacks[K] +> : ^^^^^^^^^^^^^^^^ +>source : SomeCallbacks +> : ^^^^^^^^^^^^^ +>key : K +> : ^ + + target[key] = +>target[key] = callback && ((...args) => { if (Math.random() > 0.5) { return callback(...args); } }) : (...args: Definitions[K]) => void +> : ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ +>target[key] : SomeCallbacks[K] +> : ^^^^^^^^^^^^^^^^ +>target : SomeCallbacks +> : ^^^^^^^^^^^^^ +>key : K +> : ^ + + callback && +>callback && ((...args) => { if (Math.random() > 0.5) { return callback(...args); } }) : (...args: Definitions[K]) => void +> : ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ +>callback : SomeCallbacks[K] +> : ^^^^^^^^^^^^^^^^ + + ((...args) => { +>((...args) => { if (Math.random() > 0.5) { return callback(...args); } }) : (...args: Definitions[K]) => void +> : ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ +>(...args) => { if (Math.random() > 0.5) { return callback(...args); } } : (...args: Definitions[K]) => void +> : ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ +>args : Definitions[K] +> : ^^^^^^^^^^^^^^ + + if (Math.random() > 0.5) { +>Math.random() > 0.5 : boolean +> : ^^^^^^^ +>Math.random() : number +> : ^^^^^^ +>Math.random : () => number +> : ^^^^^^ +>Math : Math +> : ^^^^ +>random : () => number +> : ^^^^^^ +>0.5 : 0.5 +> : ^^^ + + return callback(...args); +>callback(...args) : void +> : ^^^^ +>callback : (...args: Definitions[K]) => void +> : ^^^^ ^^^^^^^^^^^^^^^^^^^^^ +>...args : string | number +> : ^^^^^^^^^^^^^^^ +>args : Definitions[K] +> : ^^^^^^^^^^^^^^ + } + }); +}; + +function wrapAll(callbacks: SomeCallbacks): SomeCallbacks { +>wrapAll : (callbacks: SomeCallbacks) => SomeCallbacks +> : ^ ^^ ^^^^^ +>callbacks : SomeCallbacks +> : ^^^^^^^^^^^^^ + + const wrapped: SomeCallbacks = {}; +>wrapped : SomeCallbacks +> : ^^^^^^^^^^^^^ +>{} : {} +> : ^^ + + for (let key in callbacks) { +>key : string +> : ^^^^^^ +>callbacks : SomeCallbacks +> : ^^^^^^^^^^^^^ + + wrapCallback(callbacks, wrapped, key as keyof SomeCallbacks); +>wrapCallback(callbacks, wrapped, key as keyof SomeCallbacks) : void +> : ^^^^ +>wrapCallback : (source: SomeCallbacks, target: SomeCallbacks, key: K) => void +> : ^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^^^^^ +>callbacks : SomeCallbacks +> : ^^^^^^^^^^^^^ +>wrapped : SomeCallbacks +> : ^^^^^^^^^^^^^ +>key as keyof SomeCallbacks : keyof Definitions +> : ^^^^^^^^^^^^^^^^^ +>key : string +> : ^^^^^^ + } + return wrapped; +>wrapped : SomeCallbacks +> : ^^^^^^^^^^^^^ +} + diff --git a/tests/cases/compiler/correlatedUnions2.ts b/tests/cases/compiler/correlatedUnions2.ts new file mode 100644 index 0000000000000..1f1154aad2e1c --- /dev/null +++ b/tests/cases/compiler/correlatedUnions2.ts @@ -0,0 +1,35 @@ +// @strict: true +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/61676 + +type Definitions = { + onFoo: [arg: number]; + onBar: [arg: string]; +}; + +type SomeCallbacks = { + [K in keyof Definitions]: (...args: Definitions[K]) => void; +}; + +const wrapCallback = ( + source: SomeCallbacks, + target: SomeCallbacks, + key: K, +) => { + const callback = source[key]; + + target[key] = (...args) => { + if (Math.random() > 0.5) { + return callback(...args); + } + }; +}; + +function wrapAll(callbacks: SomeCallbacks): SomeCallbacks { + const wrapped = {} as SomeCallbacks; + for (let key in callbacks) { + wrapCallback(callbacks, wrapped, key as keyof SomeCallbacks); + } + return wrapped; +} diff --git a/tests/cases/compiler/correlatedUnions3.ts b/tests/cases/compiler/correlatedUnions3.ts new file mode 100644 index 0000000000000..f9ec97b38826b --- /dev/null +++ b/tests/cases/compiler/correlatedUnions3.ts @@ -0,0 +1,34 @@ +// @strict: true +// @noEmit: true + +type Definitions = { + onFoo: [arg: number]; + onBar: [arg: string]; +}; + +type SomeCallbacks = { + [K in keyof Definitions]?: (...args: Definitions[K]) => void; +}; + +const wrapCallback = ( + source: SomeCallbacks, + target: SomeCallbacks, + key: K, +) => { + const callback = source[key]; + target[key] = + callback && + ((...args) => { + if (Math.random() > 0.5) { + return callback(...args); + } + }); +}; + +function wrapAll(callbacks: SomeCallbacks): SomeCallbacks { + const wrapped: SomeCallbacks = {}; + for (let key in callbacks) { + wrapCallback(callbacks, wrapped, key as keyof SomeCallbacks); + } + return wrapped; +}