Typescript - 为什么不能推断出这个字符串文字类型?

Typescript - Why can't this string literal type be inferred?

以下代码段未通过类型检查:

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
    };
})

{ name: string; task: string; taskType: string; }[] is not assignable to type TaskDefinition[].

Try it

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

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

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

这里的简单解决方案是指定 map 的类型参数,这仍然会保留编译器对 map 中 return 值的检查:

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'
    };
}) 

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

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

结束编辑

您也可以直接在 return 值上键入断言,但这会禁用对 return 值的某些检查:

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

原因

编译器并未将 '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
    };
});

我看到了三种解决此问题的方法:

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
    };
});

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