Будет сложно заставить компилятор проверить, безопасна ли ваша реализация, поэтому лучшее, что я думаю, вы здесь сделаете, это то, что гарантирует, что вызывающая сторона не может вызвать его неправильно, но там, где вы используете введите assertion или «моральный эквивалент» для подавления предупреждений в реализации.
Самый простой способ сделать это - реализовать f
как перегруженную функцию :
// call signatures
function f(): undefined;
function f<T>(x: T): T;
// impl signature
function f(x?: any) {
return x;
}
Здесь вы поддерживаете две подписи вызова: либо вызов с нулевым аргументом, где результатом является undefined
, и нет параметра универсального типа, либо вызов общего назначения с одним аргументом, где результат совпадает с входным. Это должно вести себя точно так, как вы ожидаете:
var a = f(1); // number
var b = f(null); // null
var c = f(undefined); // undefined
var d = f(); // undefined
var e: number = f(); // error! undefined is not number
Перегруженная функция - это то, что я называю «морально эквивалентным» утверждению типа, потому что сигнатура реализации может быть более свободной, чем любая из сигнатур вызова. Поэтому вы должны быть осторожны, чтобы правильно реализовать эту функцию.
Если по какой-то причине вам не нужны перегрузки, вы можете использовать условные типы вместе с rest кортежами , чтобы создать обобщенную функцию, которая принимает ноль или один аргумент и тип возвращаемого значения которого равен конкретно зависит от длины списка аргументов:
function f<P extends readonly [any?]>(
...x: P
): P extends readonly [infer R] ? R : undefined {
return x as any;
}
Это ведет себя так же для примеров с a
по e
выше. Но вы все еще делаете утверждение типа (as any
в реализации), и оно более сложное и безобразное. Единственное отличие, которое я вижу, будет, если вы вызовете его с использованием аргумента типа union, например:
var hmm = f(...Math.random() < 0.5 ? ["hey"] : []) // different
, который работает для условного f
, но не для перегруженного. Я сомневаюсь, что вам это нужно.
Хорошо, надеюсь, это поможет; удачи!
Ссылка на код