Open
Description
Problem
Constructor controllers currently raise a type error when instantiated with a messenger that was defined with an incomplete list of internal actions/events, but fail to raise that error if either the Action
or Event
type union of the messenger's parent ControllerMessenger
doesn't contain any of the controller's internal actions/events.
Repro
/**
* 1. Controller constructor erroneously accepts messenger if one or more of its internal message lists are "empty"
*/
/* A. Both internal message lists are empty */
const emptyInternalMessageListsControllerMessenger = new ControllerMessenger<
// `TokenRatesControllerGetStateAction` is the only member of `TokenRatesControllerActions`
Exclude<TokenRatesControllerActions, TokenRatesControllerGetStateAction> | TokenRatesControllerAllowedActions,
// `TokenRatesControllerStateChangeEvent` is the only member of `TokenRatesControllerEvents`
Exclude<TokenRatesControllerEvents, TokenRatesControllerStateChangeEvent> | TokenRatesControllerAllowedEvents
>()
new TokenRatesController({
messenger: emptyInternalMessageListsControllerMessenger.getRestricted({
name: 'TokenRatesController',
allowedActions: [
'TokensController:getState',
'NetworkController:getNetworkClientById',
'NetworkController:getState',
'AccountsController:getAccount',
'AccountsController:getSelectedAccount',
],
allowedEvents: [
'TokensController:stateChange',
'NetworkController:stateChange',
'AccountsController:selectedEvmAccountChange'
],
}),
tokenPricesService: buildMockTokenPricesService(),
})
/* B. Only one internal message list is empty */
const emptyInternalMessageListControllerMessenger = new ControllerMessenger<
TokenRatesControllerActions | TokenRatesControllerAllowedActions,
// `TokenRatesControllerStateChangeEvent` is the only member of `TokenRatesControllerEvents`
Exclude<TokenRatesControllerEvents, TokenRatesControllerStateChangeEvent> | TokenRatesControllerAllowedEvents
>()
new TokenRatesController({
messenger: emptyInternalMessageListControllerMessenger.getRestricted({
name: 'TokenRatesController',
allowedActions: [
'TokensController:getState',
'NetworkController:getNetworkClientById',
'NetworkController:getState',
'AccountsController:getAccount',
'AccountsController:getSelectedAccount',
],
allowedEvents: [
'TokensController:stateChange',
'NetworkController:stateChange',
'AccountsController:selectedEvmAccountChange'
],
}),
tokenPricesService: buildMockTokenPricesService(),
})
// Argument of type '"TokenRatesController:getState"' is not assignable to parameter of type
// '"TokensController:getState" | "NetworkController:getNetworkClientById" | "NetworkController:getState" |
// "AccountsController:getAccount" | "AccountsController:getSelectedAccount"'.(2345)
emptyInternalMessageListsControllerMessenger.call('TokenRatesController:getState')
emptyInternalMessageListsControllerMessenger.call('NetworkController:getState')
// Argument of type '"TokenRatesController:stateChange"' is not assignable to parameter of type
// '"TokensController:stateChange" | "NetworkController:stateChange" | "AccountsController:selectedEvmAccountChange"'.(2345)
emptyInternalMessageListControllerMessenger.subscribe('TokenRatesController:stateChange', [])
/**
* 2. Controller constructor raises error when passed messenger with "incomplete" internal message lists
*/
const incompleteInternalMessageListControllerMessenger = new ControllerMessenger<
| Extract<
AccountsControllerActions,
| AccountsControllerGetAccountAction
| AccountsControllerGetSelectedAccountAction
>
| AccountsControllerAllowedActions,
| Extract<
AccountsControllerEvents,
AccountsControllerSelectedEvmAccountChangeEvent
>
| AccountsControllerAllowedEvents
>()
new AccountsController({
// Type 'ControllerMessenger<AccountsControllerGetAccountAction | AccountsControllerGetSelectedAccountAction
// | AccountsControllerAllowedActions, AccountsControllerSelectedEvmAccountChangeEvent | AccountsControllerAllowedEvents>'
// is not assignable to type 'AccountsControllerMessenger'.
// Property '#private' in type 'ControllerMessenger' refers to a different member
// that cannot be accessed from within type 'RestrictedControllerMessenger'.(2322)
// AccountsController.d.ts(102, 9): The expected type comes from property 'messenger'
// which is declared here on type '{ messenger: AccountsControllerMessenger; state: AccountsControllerState; }'
messenger: incompleteInternalMessageListControllerMessenger,
state: {
internalAccounts: {
accounts: {},
selectedAccount: '',
},
},
})
Acceptance Criteria
Controllers inheriting from BaseControllerV2
must raise a type and/or runtime error if they are initialized with a messenger that is derived from an unrestricted ControllerMessenger
that does not contain any of the controller's internal actions and/or events.