2017-02-21 5 views
1

У меня есть функция высшего порядка, например, в ванильных JS, как это:Как правильно ввести функцию высшего порядка

function log(fn) { 
    return (...args) => { 
    console.log("Calling", fn.name); 
    return fn(...args); 
    } 
} 

И используются так:

let name; 
const setName = log((newName) => { 
    name = newName; 
}); 
setName("Hello"); // output "Calling setName" 

Как правильно ввести это в TS, так что setName имеет правильную сигнатуру функции? Значение:

setName("hello") // OK 
setName() // Error, missing arg 
setName(123) // Error, number not string 

То, что я придумал до сих пор:

function log<F extends Function>(fn: F): F { 
    return (...args: any[]) => { 
    console.log("Calling", fn.name); 
    return fn(...args); 
    } 
} 

let name; 
const setName = log((newName: string) => { 
    name = newName; 
}); 

Который работает так, как я хочу (я получаю проверку на setName тип аргумента), но я получаю ошибку компиляции на log функция возврата:

Error: TS2322:Type '(...args: any[]) => any' is not assignable to type 'F'.

Даже если я использую <F extends (...args: any[]) => any> я получаю ту же ошибку. В принципе, я не знаю, как заставить возвращаемую функцию удовлетворять общему типу F.

Как я могу это сделать?

ответ

2

С функцией перегружать

Function overloads может быть использован. Это способ отделить определение от реализации:

function log<F extends Function>(fn: F): F 
function log(fn: Function) { 
    return (...args) => { 
     console.log("Calling", fn.name); 
     return fn(...args); 
    } 
} 

Мне нравится версия от перегрузки, так как она позволяет производить определения машинопись, когда модуль распространяется в виде скомпилированного пакета НПМ.

С типа утверждения as F

типа Function слишком широк. Ваша завернутая функция должна быть подтипом: (...args: any[]) => any.

Вы можете использовать as F для того, чтобы сказать машинопись, чтобы быть уверенным в возвращаемой функции:

function log<F extends (...args: any[]) => any>(fn: F): F { 
    return ((...args: any[]) => { 
     console.log("Calling", fn.name); 
     return fn(...args); 
    }) as F 
} 

с типом утверждения as any

же реализация, но мы можем использовать Function и as any вместо (...args: any[]) => any и as F (см. ответ Луи).

+0

Спасибо, я не думал об использовании перегрузок функций, подобных этому. – Aaron

+0

Я отредактировал с идеей другого автора. Тип 'Функция' слишком широк. Ваша завернутая функция должна иметь тип: '(... args: any []) => any'. – Paleo

+0

Интересно, я попробовал 'F extends (...args: any []) => any' с моим исходным кодом, и по какой-то причине он по-прежнему не позволял мне возвращаться даже с такой точной сигнатурой, а 'как F' не работал с' F extends Function'. Честно говоря, я не понимаю, почему это другое, но оно работает. – Aaron

2

Самый простой модификации вы можете сделать, чтобы заставить тип вашего возвращаемого значения для any:

function log<F extends Function>(fn: F): F { 
    return ((...args: any[]) => { 
    console.log("Calling", fn.name); 
    return fn(...args); 
    }) as any; 
} 

Это компилирует файл, и делать это, ваша setName функция будет иметь ту же сигнатуру, что вы передаете до log.

+0

Спасибо, я нашел, что это работает, но я не люблю использовать 'как любой' ... также, почему не работает функция' as Function'? – Aaron

+0

Использование 'как любой' не хуже, чем использование' как F', как в другом ответе. В любом случае, вы говорите компилятору: «Поверьте мне, я знаю, что я делаю». 'as Function' не может работать, потому что' F' определяется параметром, который вы передаете. на журнал. Если 'F' является расширением' Function', присваивая объект типа 'F' переменной, которая может принимать объекты типа' Function', отлично, но присваивает объект типа 'Function' переменной, которая может принимать объекты типа 'F' не в порядке. Вы по существу пытаетесь сделать последнее, если используете 'как функцию' вместо' как любой'. – Louis

+0

Вижу, спасибо за объяснение. В основном это потому, что вы не можете назначить базовый тип подтипу. – Aaron

Смежные вопросы