You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让TypeScript为泛型ternary函数自动实现非空断言?

问题:让TypeScript自动推导三元工具函数中condition为真时的非空类型

我写了一个泛型工具函数ternary,用来抽象三元运算符逻辑,当condition为假值时默认返回undefined,代码如下:

export const ternary = <TReturn, TDefault = undefined>(
    condition: unknown,
    returnValue: TReturn,
    defaultValue?: TDefault,
) => {
    if (!condition) return defaultValue;
    return returnValue;
};

在使用这个函数时,比如在findAllUsers方法里传入input.cursor作为condition——明明当condition为真时input.cursor肯定是非空的,但TypeScript还是报错提示input.cursor可能为undefined。目前我只能手动加非空断言!,想知道怎么让TypeScript自动完成这个类型推导,不用手动加断言。

使用场景的报错代码:

findAllUsers = (
        ctx: TRPCContext<"authenticated">,
        input: PaginationSchema,
    ) => {
        return ctx.db.query.users.findMany({
            limit: input.limit,
            where: ternary(input.cursor, gt(users.id, input.cursor)),
        });
    };

手动添加断言的代码:

findAllUsers = (
        ctx: TRPCContext<"authenticated">,
        input: PaginationSchema,
    ) => {
        return ctx.db.query.users.findMany({
            limit: input.limit,
            where: ternary(input.cursor, gt(users.id, input.cursor!)),
        });
    };

解决方案

要让TypeScript自动识别condition为真时的非空类型,需要给ternary函数的泛型和参数加上类型约束,把condition和returnValue的类型关联起来。最直观的方式是把returnValue改成回调函数,让TypeScript明确知道:只有当condition为真(非空)时,这个回调才会被执行,回调里的参数自然就是非空的。

修改后的ternary函数代码:

export const ternary = <TCondition, TReturn, TDefault = undefined>(
  condition: TCondition,
  returnValue: (condition: NonNullable<TCondition>) => TReturn,
  defaultValue?: TDefault,
) => {
  if (!condition) return defaultValue;
  return returnValue(condition as NonNullable<TCondition>);
};

对应的使用方式:

findAllUsers = (
  ctx: TRPCContext<"authenticated">,
  input: PaginationSchema,
) => {
  return ctx.db.query.users.findMany({
    limit: input.limit,
    where: ternary(input.cursor, (cursor) => gt(users.id, cursor)),
  });
};

为什么这样可行?

通过回调的方式,我们把input.cursor的非空判断逻辑交给了ternary函数内部——TypeScript能推导出来:只有当condition为真时,回调才会被调用,所以回调里的cursor参数自动被标记为NonNullable<typeof input.cursor>,完全不需要手动加非空断言。

如果不想用回调,也可以通过条件类型来实现,但回调的方式更符合TypeScript的类型推导逻辑,代码可读性也更高。


内容的提问来源于stack exchange,提问作者Zihao Lam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 08:12:48