我有一个流程,在该流程中,我不想添加大量 if 语句,而是创建一个保存所需信息的对象,以便在执行时以更线性的方式读取。我在下面创建了一个简单且人为的示例。
type ItemOne = {
type: 'itemOne'
fn: typeof funcOne
args: Parameters<typeof funcOne>[0]
}
type ItemTwo = {
type: 'itemTwo',
fn: typeof funcTwo
args: Parameters<typeof funcTwo>[0]
}
type Item = ItemOne | ItemTwo
function funcOne({ name }: { name: string }) {
console.log(name)
}
function funcTwo({ age }: { age: number }) {
console.log(age)
}
function createItem(shouldCreateItemOne: boolean): Item {
if (shouldCreateItemOne) {
return { type: 'itemOne', fn: funcOne, args: { name: 'Dave' } } as const
}
return { type: 'itemTwo', fn: funcTwo, args: { age: 22 } } as const
}
const item = createItem(false)
item.fn(item.args)
当我开始调用函数item.fn(item.args)
时,TypeScript 提示Argument of type '{ name: string; } | { 年龄:数字; }' 不可分配给类型为 '{ name: string; 的参数; } & { 年龄:数字; }'.
有没有办法确保 TypeScript 可以保留 item.args
的缩小版本?
TypeScript playground 中还有一个示例链接
最佳答案
这看起来像是 overloads 的工作,您希望返回类型根据给定参数的类型进行更改:
function createItem(shouldCreateItemOne: true): ItemOne;
function createItem(shouldCreateItemOne: false): ItemTwo;
function createItem(shouldCreateItemOne: boolean): Item;
function createItem(shouldCreateItemOne: boolean): Item {
if (shouldCreateItemOne) {
return { type: 'itemOne', fn: funcOne, args: { name: 'Dave' } } as const
}
return { type: 'itemTwo', fn: funcTwo, args: { age: 22 } } as const
}
如果您不希望支持使用通用 boolean
类型调用函数,则最后一个重载是可选的。使用重载允许 TypeScript 推断出此调用的正确类型:
const item = createItem(false)
// ^? ItemTwo
item.fn(item.args) // okay
如果您有两个以上的项目并且需要更大的灵活性,那么这可能不是最适合您的。请参阅@jcalz's comment使用通用索引访问的替代方案。
您还可以将 Item 类型重构到 map 中:
interface ItemMap {
itemOne: typeof funcOne;
itemTwo: typeof funcTwo;
}
type Item<K extends keyof ItemMap = keyof ItemMap> = {
[P in K]: { type: P; fn: ItemMap[P]; args: Parameters<ItemMap[P]>[0] };
}[K];
createItem
声明现在看起来像
function createItem(shouldCreateItemOne: true): Item<"itemOne">;
function createItem(shouldCreateItemOne: false): Item<"itemTwo">;
function createItem(shouldCreateItemOne: boolean): Item;
function createItem(shouldCreateItemOne: boolean): Item {
关于typescript - 确保 TypeScript 联合在整个代码中保持狭窄,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75794155/