typescript 如何获得泛型可选函数参数的正确类型推断?

dy2hfwbg  于 2023-03-19  发布在  TypeScript
关注(0)|答案(2)|浏览(199)

请看下面的代码(playground link):

function combine<F extends Record<string, string>, B extends Record<string, string>>(foo: F, bar?: B) {
    const retVal = {
        ...foo,
        ...bar
    }

    return retVal
}

const test = combine({
    one: 'One',
}, {
    two: 'Two',
})

function testKey<T extends Record<string, string>>(foo: T, bar: keyof T) { }
testKey(test, 'one')   // Valid
testKey(test, 'two')   // Valid
testKey(test, 'three') // Shouldn't be valid

第19行不应该是有效的,但它是有效的。如果我将鼠标悬停在retVal上,推断的类型是:

const retVal: F & {
    [x: string]: string;
}

但是我不知道为什么会这样推断,因为它太宽松了,如果我把它修改成bar不是可选的,那么retVal的推断类型是:

const retVal: F & B

这就是我想要的类型推断,但是当bar是可选的时候,我找不到一种方法来获得它。

esbemjvw

esbemjvw1#

使用Object.assign创建正确的交点类型,并使B默认为{}

function combine<F extends Record<string, string>, B extends Record<string, string> = {}>(foo: F, bar?: B) {
    const retVal = Object.assign({}, foo, bar);

    return retVal
}

Playground

wgeznvg7

wgeznvg72#

您可以使用函数重载来帮助编译器:

function combine<F extends Record<string, string>>(foo: F): F;
function combine<F extends Record<string, string>, B extends Record<string, string>>(foo: F, bar: B): F & B;
function combine<F extends Record<string, string>, B extends Record<string, string>>(foo: F, bar?: B) {
    const retVal = {
        ...foo,
        ...bar
    };

    return retVal;
}

const test = combine({
    one: 'One',
}, {
    two: 'Two',
})

function testKey<T extends Record<string, string>>(foo: T, bar: keyof T) { }
testKey(test, 'one')   // Valid
testKey(test, 'two')   // Valid
testKey(test, 'three') // Not valid

Playground链接

相关问题