Я бы сказал, что главная проблема здесь в том, что функция декоратора с карри не может определить спецификацию для параметра типа K
(или параметра типа T
) при его использовании. Если у вас есть функция curry generi c с типом, подобным:
declare const curryBad: <T, U>(t: T) => (u: U) => [T, U]
, компилятор попытается вывести T
и U
при ее вызове. Допустим, вы звоните curryBad(1)
. Значение 1
приводит к выводу T
как number
. Но здесь нет значения типа U
, поэтому вывод типа завершается неудачно для U
и становится unknown
. Поэтому результат curryBad(1)
равен (u: unknown) => [number, unknown]
:
const bad = curryBad(1)(""); // [number, unknown]
Хотя не исключено, что компилятор может теоретически отложить вывод U
до вызова возвращаемой функции, это не так, как он работает на практике , Вместо этого вы можете просто написать сигнатуру функции для начала: не объявляйте U
как параметр исходной функции; вместо этого объявите его как параметр возвращаемой функции:
declare const curryGood: <T>(t: T) => <U>(u: U) => [T, U]
Теперь вызов curryGood(1)
вернет значение типа <U>(u: U) => [number, U]
, что, вероятно, то, что вы хотите:
const good = curryGood(1)(""); // [number, string]
Имея это в виду, я бы предложил переместить ваш параметр K
. Кроме того, я не уверен, что вам действительно нужно, чтобы T
был его собственным типом generi c; Record<K, V>
может быть достаточно хорошо. Но если вы обнаружите, что вам это нужно, его также следует переместить вместе с K
:
export function Default<V>(
param: DefaultParam<V>): <K extends PropertyKey>(t: Record<K, V>, p: K) => void {
return <K extends PropertyKey>(target: Record<K, V>, propertyKey: K) => {
};
}
И теперь ваш декоратор должен работать, как нужно:
class Good {
@Default(() => new Date()) // no error
test!: Date;
}
class Bad {
@Default(123) // error! Date is not number
test!: Date;
}
Хорошо, надеюсь, это поможет; удачи!
Детская площадка ссылка на код