我有一个函数,我希望它根据参数 props 返回 2 种不同的类型。
interface IPaginateParams {
perPage: number;
currentPage: number;
isFromStart?: boolean;
}
interface IWithPagination<Data, TParams extends IPaginateParams = IPaginateParams> {
data: Data;
pagination: IPagination<TParams>;
}
type IPagination<TParams> = TParams extends
| { currentPage: 1 }
| { isFromStart: true }
| { isLengthAware: true }
? ILengthAwarePagination
: IBasePagination;
interface IBasePagination {
currentPage: number;
perPage: number;
from: number;
to: number;
}
interface ILengthAwarePagination extends IBasePagination {
total: number;
lastPage: number;
}
function paginate<TData = any[], TParams extends IPaginateParams = IPaginateParams>(
options: TParams
): IWithPagination<TData, TParams>;
这个想法是,如果您传递 currentPage: 1
或 isFromStart: true
,它应该向 pagination
对象添加 2 个额外的类型。
奇怪的是 IWithPagination
按预期工作,
const data = {} as IWithPagination<any, {perPage: 2, currentPage: 1}>;
expectType<ILengthAwarePagination>(data.pagination);
但是当我使用调用时,它总是返回 IBasePagination
const data = paginate({perPage: 2, currentPage: 1});
expectType<ILengthAwarePagination>(data.pagination) // fails
// or
const data = paginate({perPage: 2, currentPage: 2, isFromStart: true});
expectType<ILengthAwarePagination>(data.pagination) // fails
答案 0 :(得分:1)
正如@OlegValter 在评论中所解释的,当将对象传递给 paginate
时,它推断为扩展类型,例如:
{perPage: 2, currentPage: 2, isFromStart: true} // inferred as {perPage: number; currentPage: number; isFromStart: boolean}
因此,返回类型的检查总是回退到 IBasePagination
类型(else 子句)。
我们需要做的就是指定函数的参数是readonly
。
declare function paginate<TData = any[], TParams extends IPaginateParams = IPaginateParams>(
options: Readonly<TParams>
// ---------^ this is what made the input as a narrow type
): IWithPagination<TData, TParams>;
工作example