Я с большим успехом использовал условные типы машинописи, но часто обнаруживаю, что, хотя я могу выражать сигнатуры типов, при реализации функций я должен использовать any
, хотя я знаю, что реализация верна.
Пример, это определение:
type ExportType<InputType extends string|undefined> =
string extends InputType ? undefined : ()=>void;
function convert<InputType extends string|undefined>(input: InputType): ExportType<InputType>;
(я знаю, что мог бы использовать перегрузки, но моя реальная проблема более сложна, и перегрузки не были бы реалистичны для реальной проблемы)
В сущности, подпись говорит "если параметр string
, я верну ()=>void
, если это undefined
, я верну undefined
.
И это прекрасно работает. Игра с convert("x")
и convert(undefined)
показывает, что машинопись соответствует этому определению.
Однако при попытке реализовать эту функцию:
type ExportType<InputType extends string|undefined> =
string extends InputType ? undefined : ()=>void;
function convert<InputType extends string|undefined>(input: InputType): ExportType<InputType> {
if (input) {
return ()=>{console.log("OK");};
} else {
return undefined;
}
}
Это не компилируется. Машинопись говорит:
error TS2322: Type '() => void' is not assignable to type 'ExportType<InputType>'.
return ()=>{console.log("OK");};
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Но эта строка находится в if (input)
, поэтому в этот момент мы знаем, что ввод не undefined
, поэтому он должен быть string
, и поэтому мы должны вернуть () => void
... Но, похоже, компилятор просто недостаточно умен, чтобы это увидеть.
Изменение этой строки на:
return <any>(()=>{console.log("OK");});
Заставляет это работать, но это разочаровывает ...
Так есть ли способ написать полностью безопасную и проверенную реализацию этой сигнатуры, которую машинопись позволяет нам выразить?