【发布时间】:2021-03-08 01:06:58
【问题描述】:
我有一个函数,我希望它根据其参数 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
【问题讨论】:
-
能否请您在 TS 操场上分享完全可重现的示例,这样会更容易提供帮助
-
原因很简单——类型加宽。如果你检查你的函数调用,你会发现参数不是一个字面量,而是一个推断的
{ currentPage: number; perPage: number;},显然,它不是{ currentPage: 1 }或{ isFromStart: true }的子类型,而是第一个的超类型,因此extends子句失败,编译器将其解析为IBasePagination。解决方法:在字面上使用as const -
@captain-yossarian - 谢谢,我还注意到我夸大了类型是 both 的超类型,当然它还没有更正。跨度>
-
@OlegValter,谢谢你的解释!我可以把它作为 const 放在函数定义中的某个地方吗?这些方法和类型是我正在维护的库的一部分
-
只读参数有效!谢谢@OlegValter
标签: typescript typescript-generics