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

TypeScript拼接已知字符串类型时如何推断模板字面量类型

TypeScript 字符串字面量拼接类型推导问题

问题背景

现有两个类型定义:Action 和 ActionEmitter,ActionEmitter由Action派生,规则为在Action的所有字符串字面量成员后追加固定后缀'Clicked'。
需要实现一个入参类型为Action、返回值类型为ActionEmitter的函数,期望TypeScript可以直接识别入参与'Clicked'拼接后的结果为合法的ActionEmitter类型,不需要额外编写类型守卫或类型转换逻辑。
原有代码如下:

type Action = 'next' | 'previous';

type ActionEmitter = Action extends `${infer u}` ? `${u}Clicked` : never;

function isActionEmitter(s: string | ActionEmitter): s is ActionEmitter {
  switch (s) {
    case 'previousClicked':
    case 'nextClicked':
      return true;
    default:
      return false;
  }
}

// 可正常运行但存在冗余逻辑
function createActionEmitterGood(action: Action): ActionEmitter | null {
  const emitter = action + 'Clicked';
  return (isActionEmitter(emitter) && emitter) || null;
}

// 类型报错:Type 'string' is not assignable to type '"nextClicked" | "previousClicked"'
function createActionEmitterBad(action: Action): ActionEmitter | null {
  const clicked = 'Clicked' as const;
  return action + clicked;
}

createActionEmitterGood通过类型守卫实现了需求但写法冗余,createActionEmitterBad直接拼接字符串会触发类型错误,目标是在不使用类型守卫、不做强制类型转换的前提下实现合法的函数逻辑。

实现方案

报错的核心原因:TypeScript 不会对+运算符拼接的字符串结果做模板字面量类型推导,所有通过+拼接得到的字符串,默认会被拓宽为string类型,无法匹配ActionEmitter这种精确的字面量联合类型。

不需要额外的校验或类型断言,只需要将+拼接替换为TypeScript的模板字符串语法即可,TS会对模板字符串形式的字面量拼接做精确的类型推导。同时由于入参已经被约束为合法的Action类型,拼接结果必然是合法的ActionEmitter成员,不需要返回null兜底。

最终可通过类型校验的代码如下:

type Action = 'next' | 'previous';
// ActionEmitter可以直接简化定义,和原有条件推导的效果完全等价
type ActionEmitter = `${Action}Clicked`;

function createActionEmitter(action: Action): ActionEmitter {
  return `${action}Clicked`;
}

以上代码无任何类型报错:传入'next'时TS自动推导返回值为'nextClicked',传入'previous'时自动推导返回值为'previousClicked',完全匹配ActionEmitter类型约束。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 14:15:41