【问题标题】:Typescript - Why can't this string literal type be inferred?Typescript - 为什么不能推断出这个字符串文字类型?
【发布时间】:2026-01-27 08:45:01
【问题描述】:

下面的sn-p没有通过类型检查:

type TaskType = 'SIMPLE' | 'COMPLEX'

interface TaskDefinition {
    name: string,
    task: string,
    taskType: TaskType
};

const test: TaskDefinition = { 
    name: '',
    task: '',
    taskType: 'SIMPLE' // This is fine
};

const tasks : TaskDefinition[] = ["apples", "pears"].map(i => {
    return {
        name: i,
        task: i,
        taskType: 'SIMPLE' // This one is not
    };
})

{ 名称:字符串;任务:字符串;任务类型:字符串; }[] 不可分配 键入 TaskDefinition[]。

Try it

似乎taskType 被推断为string 而不是TaskType,尽管目标类型是TaskDefinition

这是什么原因造成的,我该如何解决?

【问题讨论】:

    标签: typescript types literals


    【解决方案1】:

    只有当您将其分配给 const 时,Typescript 才会推断字符串文字类型。当您创建对象文字时,编译器将为字符串常量而不是字符串文字类型推断 string。如果您将对象文字直接分配给需要字符串文字类型的东西,那没关系,因为在这种情况下,编译器只会检查字符串常量是否可分配给字符串文字类型。

    这里的简单解决方案是为map 指定类型参数,这仍将保留编译器对来自map 的返回值的检查:

    const tasks = ["apples", "pears"].map<TaskDefinition>(i => {
        return {
            name: i,
            task: i,
            taskType: 'SIMPLE'
        };
    })
    

    或者在字符串上使用类型断言到预期的字符串字面量类型:

    const tasks:TaskDefinition[] = ["apples", "pears"].map(i => {
        return {
            name: i,
            task: i,
            taskType: 'SIMPLE' as 'SIMPLE'
        };
    }) 
    

    编辑 从 typescript 3.4 (PR) 开始,您还可以使用 as const 断言来获取字符串文字类型:

    const tasks:TaskDefinition[] = ["apples", "pears"].map(i => {
        return {
            name: i,
            task: i,
            taskType: 'SIMPLE' as const
        };
    }) 
    

    结束编辑

    您也可以直接在返回值上键入 assert,但这会禁用对返回值的一些检查:

    const tasks:TaskDefinition[] = ["apples", "pears"].map(i => {
        return <TaskDefinition>{
            wrongValue: "", // no error since we are asserting
            name: i,
            task: i,
            taskType: 'SIMPLE'
        };
    }) 
    

    【讨论】:

    • 我同意.map&lt;TaskDefinition&gt; 可能是最优雅的解决方案。
    • @Fenton 10x,我还添加了为什么在 map 上指定类型参数优于直接类型断言的原因
    【解决方案2】:

    原因

    编译器不会将 'SIMPLE' 从字符串缩小到 TaskType,因此您需要通过类型断言来帮助它。有两种选择。

    对象的类型断言

    const tasks: TaskDefinition[] = ["apples", "pears"].map(i => {
        return <TaskDefinition> {
            name: i,
            task: i,
            taskType: 'SIMPLE' // This one is not
        };
    });
    

    在值处类型断言

    const tasks: TaskDefinition[] = ["apples", "pears"].map(i => {
        return {
            name: i,
            task: i,
            taskType: <TaskType>'SIMPLE' // This one is not
        };
    });
    

    【讨论】:

      【解决方案3】:

      我看到了三种解决方法:

      return {
              name: i,
              task: i,
              taskType: 'SIMPLE'
          } as TaskDefinition;
      

      或者:

      const tasks: TaskDefinition[] = ["apples", "pears"].map(i => {
          return {
              name: i,
              task: i,
              taskType: 'SIMPLE'
          };
      }) as TaskDefinition[];
      

      或者:

      const tasks: TaskDefinition[] = ["apples", "pears"].map(i => {
          return {
              name: i,
              task: i,
              taskType: 'SIMPLE' as TaskType
          };
      });
      

      至于为什么,我不完全确定。为什么不使用字符串枚举来代替自定义字符串类型?

      【讨论】: