Reputation: 14755
Consider the following code:
const subscriptions: { [key: string]: [() => void] } = {}
interface ISubscription {
eventName: string
callback: () => void
}
export function unsubscribe({ eventName, callback }: ISubscription) {
if (!subscriptions[eventName]) { return }
const index = subscriptions[eventName].findIndex((l) => l === callback)
if (index < 0) { return }
subscriptions[eventName].splice(index, 1)
}
export function subscribe({ eventName, callback }: ISubscription) {
if (!subscriptions[eventName]) {
subscriptions[eventName] = []
}
subscriptions[eventName].push(callback)
return () => unsubscribe({ eventName, callback })
}
The issue typescript reports is:
TS2741: Property '0' is missing in type '[]' but required in type '[() => void]'.
Which comes from trying to assign an empty array to the subscriptions
:
if (!subscriptions[eventName]) {
subscriptions[eventName] = []
}
This can be fixed by defining the interface to accept an empty array but then there's an issue when assigning a callback:
const subscriptions: { [key: string]: [() => void] | [] } = {}
TS2345: Argument of type '() => void' is not assignable to parameter of type 'never'.
A workaround would be:
const subscriptions: { [key: string]: [() => void] } = {}
if (!subscriptions[eventName]) {
subscriptions[eventName] = [callback]
}
else {
subscriptions[eventName].push(callback)
}
What is the correct way to be able to set it to an empty array and then assign the callback? I tried using the question mark too but I can't seem to get it right. Thank you for your help.
Upvotes: 0
Views: 2686
Reputation: 2972
type TCallBackArray = (() => void)[];
interface ISubscriptions {
[key: string]: TCallBackArray
};
const subscriptions: ISubscriptions = {}
Where TCallBackArray
is defined as an array of functions
, and ISubscriptions
is defined as an indexer.
Upvotes: 1
Reputation: 3924
This is a common misconception. [() => void]
is a tuple of one element, and that element needs to satisfy the type () => void
. If you want an array, let it be empty or not, with one or multiple elements, the correct type is (() => void)[]
.
The following expressions are accepted by (() => void)[]
:
[]
[() => { doSomething(); }]
[() => { doSomething(); }, () => { doSomethingElse(); }]
While only the expression number 2 is accepted by [() => void]
.
If you want either an empty array or a tuple of one element, you can just do [] | [() => void]
Upvotes: 2
Reputation: 5639
You can simply define it as an "array of type":
type Subscriptions = {
[key: string]: Array<()=>void>
}
then:
const subscriptions: Subscriptions = {}
if (!subscriptions[eventName]) {
subscriptions[eventName] = []
}
Upvotes: 1