J'ai cette configuration d'événement personnalisé, et cela fonctionne avec TypeScript 2.5.3
, mais lorsque j'ai mis à jour à 2.6.1
, une erreur s'est produite.
window.addEventListener('OnRewards', (e: CustomEvent) => {
// my code here
})
[ts] L'argument de type '(e: CustomEvent) => void' n'est pas assignable au paramètre de type 'EventListenerOrEventListenerObject'.
Le type '(e: CustomEvent) => void' n'est pas assignable au type 'EventListenerObject'.
La propriété 'handleEvent' est manquante dans le type '(e: CustomEvent) => void'.
Je ne sais pas exactement quoi faire ici pour résoudre ce problème.
Cela est dû au comportement de l'indicateur --strictFunctionTypes
compiler ajouté dans TypeScript v2.6. Une fonction de type (e: CustomEvent) => void
n'est plus considérée comme une instance valide de EventListener
, qui prend un paramètre Event
, pas une CustomEvent
.
Donc, un moyen de résoudre ce problème consiste à désactiver --strictFunctionTypes
.
Une autre méthode consiste à transmettre une fonction qui prend une Event
et se réduit ensuite à CustomEvent
via un garde type:
function isCustomEvent(event: Event): event is CustomEvent {
return 'detail' in event;
}
window.addEventListener('OnRewards', (e: Event) => {
if (!isCustomEvent(e))
throw new Error('not a custom event');
// e is now narrowed to CustomEvent ...
// my code here
})
Une troisième méthode consiste à utiliser l’autre surcharge de addEventListener()
:
addEventListener<K extends keyof WindowEventMap>(type: K, listener: (this: Window, ev: WindowEventMap[K]) => any, useCapture?: boolean): void;
Si le paramètre type
est le nom d'un type d'événement connu (K extends keyof WindowEventMap
) tel que "onclick"
, la fonction listener
s'attend à ce que son paramètre soit de ce type d'événement restreint (WindowEventMap[K]
). Le problème est que "OnRewards"
n'est pas un type d'événement connu ... sauf si vous utilisez déclaration fusionnant avec make le connu:
// merge into WindowEventMap
interface WindowEventMap {
OnRewards: CustomEvent
}
Ou, si vous êtes dans un module (quelque chose contenant export
dans celui-ci), utilisez augmentation globale :
// merge into WindowEventMap
declare global {
interface WindowEventMap {
OnRewards: CustomEvent
}
}
Ensuite, utilisez votre code comme avant:
// no error!
window.addEventListener('OnRewards', (e: CustomEvent) => {
// my code here
})
Donc, ce sont vos options. Lequel vous voulez choisir est à vous. J'espère que cela pourra aider; bonne chance!
En vous basant sur l'excellente réponse de jcalz , vous pouvez également utiliser une assertion de type pour être un peu plus propre:
window.addEventListener('OnRewards', (e: Event) => {
const detail = (<CustomEvent>e).detail;
...
});
Vous avez aussi cette option:
window.addEventListener('OnRewards', (e: CustomEvent) => {
// your code here
} as (e: Event) => void)
J'ai créé une fonction générique basée sur la réponse de @ jcalz
/**
* Checks whether an object can be safely cast to its child type
* @param parent the object to be 'narrowly' cast down to its child type
* @param checkForProps props which aught to be present on the child type
*/
export function isSubTypeWithProps<P, C extends P>(parent: P, ...checkForProps: (keyof C)[]): parent is C {
return checkForProps.every(prop => prop in parent);
}
/**
* Usage example
*/
const el = document.getElementById('test');
el.addEventListener('click', (e: Event) => {
if (isSubTypeWithProps<Event, MouseEvent>(e, 'which')) {
if (e.which === 1) { // primary mouse button only ('which' prop is only available on MouseEvent)
console.log('clicked');
}
}
});