取以下代码(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是可选的时候,我想不出一种方法来获得它.

推荐答案

您可以使用function overloads来帮助编译器:

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 link

Typescript相关问答推荐

有没有办法适当缩小类型?

使用带有RxJS主题的服务在Angular中的组件之间传递数据

使用React处理Websocket数据

为什么typescript不能推断类的方法返回类型为泛型''

动态调用类型化函数

接口的额外属性作为同一接口的方法的参数类型'

STypescript 件的标引签名与功能签名的区别

在类型脚本中的泛型类上扩展的可选参数

如何创建一家Reduxstore ?

垫表页脚角v15

笛卡尔产品类型

如何过滤文字中的类对象联合类型?

如何使用TypeScrip在EXPO路由链路组件中使用动态路由?

类型实例化过深,可能是无限的&TypeScrip中的TupleUnion错误

错误TS7030:并非所有代码路径都返回值.";由tsfig.json中的";Strong";:False引起

为什么看起来相似的代码在打字时会产生不同的错误?

导航链接不触发自定义挂钩

Typescript泛型-键入对象时保持推理

在Typescript 中,是否有一种方法来定义一个类型,其中该类型是字符串子集的所有可能组合?

解析错误:DeprecationError: 'originalKeywordKind' 自 v5.0.0 起已被弃用,无法再使用