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[].
似乎 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
};
});
至于为什么,我不太确定。为什么不使用字符串枚举代替自定义字符串类型?
以下代码段未通过类型检查:
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[].
似乎 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
};
});
至于为什么,我不太确定。为什么不使用字符串枚举代替自定义字符串类型?