2017-01-21 5 views
2

Для целей тестирования я должен высмеять window.addEventListener (с шуточкой пустой макет достаточно просто для шпиона). Так что я так люблю:Как переопределить тип window.addEventListener в TypScript?

window.addEventListener = jest.fn(); 
window.removeEventListener = jest.fn(); 

Проблема заключается в том, когда я window.addEventListener.mockClear() машинописи жалуется, что метод не существует.

enter image description here

Какой самый лучший способ справиться с этим?

Обход: на данный момент я делаю это, но я не хотел бы делать это все время

(window.addEventListener as jest.Mock<{}>).mockClear(); 
(window.addEventListener as jest.Mock<{}>).mockClear(); 

ответ

1

Я не думаю, что это возможно, чтобы увеличить существующий интерфейс для добавления некоторых свойств к способам, объявленным в этом интерфейсе.

Но вы можете переопределить эти методы. Существует способ избежать написания типов бросков все время: вы можете определить свой собственный интерфейс MockWindow, имеющий addEventListener и removeEventListener, набранный по мере необходимости. Тогда вы можете бросить реальный window объект MockWindow один раз и использовать его впоследствии:

interface MockWindow extends Window { 
    addEventListener: jest.Mock<{}> & typeof window.addEventListener; 
    removeEventListener: jest.Mock<{}> & typeof window.removeEventListener; 
} 

function mockWindow() { 
    window.addEventListener = jest.fn(); 
    window.removeEventListener = jest.fn(); 
    return window as MockWindow; 
} 

let w = mockWindow(); 


w.addEventListener('load',function() {}); 
w.addEventListener.mockClear(); 

На самом деле, потому что в текущей версии шутя типизации, jest.Mock интерфейс уже имеет очень рыхлую вызов подписи

interface Mock<T> extends Function { 
    ... 
    (...args: any[]): any; 

ничего объявленную поскольку jest.Mock можно вызывать с любым количеством любых параметров, и это делает ненужным добавление & typeof window.addEventListener к типу addEventListener.

UPDATE: оказывается машинопись достаточно выразительным, так что вы можете написать универсальный, тип проверил функцию:

function mockMethods<T, MethodName extends keyof T>(o: T, methodNames:MethodName[]) 
: T & {[K in MethodName]: T[K] & jest.Mock<{}>} { 
    methodNames.forEach(k => { 
     o[k] = jest.fn() as any; 
    }); 
    return o as any; // typescript doesn't allow this cast: 
        // as (T & {[K in MethodKeys]: T[K] & jest.Mock<{}>}); 
} 

let w = mockMethods(window, ['addEventListener', 'removeEventListener']); 

w.addEventListener('load', function() {}); 
w.addEventListener.mockClear(); 

// you can still call other window methods 
w.alert('x'); 

// and their types are unaffected 
w.alert.mockClear(); // error: Property 'mockClear' does not exist 
        // on type '(message?: any) => void'. 

// and you can't mock non-existent methods 
let u = mockMethods(window, ['z']); // error: Argument of type '"z"[]' 
        // is not assignable to parameter of type '("blur" | ... 
+0

Спасибо большое, очень чистый, лаконичный и ясный ответ. Работает как шарм :) –