Link to playground with an example.
我有一个复杂的接口,它有两个属性:
- 一个
attributes
人的数组 - 记录
initialValues
,其中关键字必须来自属性数组(但不是所有属性,因此它应该是部分的)
export interface Data<
TAttributes extends string,
> {
readonly attributes?: readonly TAttributes[]
readonly initialValues?: {
readonly [TKey in TAttributes & {}]?: string
}
}
当我的对象只是一个普通对象时,它可以工作,当initialValues
声明不是attributes
一部分的键时,我会得到一个错误.
function data<TAttributes extends string>(data: Data<TAttributes>): Data<TAttributes> {
return data
}
const okay = data({
attributes: ['firstName'],
initialValues: {
firstName: 'value',
age: 2 // error here - which is correct
},
})
但当我的参数实际上是返回那种对象(Data
)的函数时-它不会.当添加不同的属性名而不是attributes
的一部分时,由于奇怪的失败推理,推断出的额外属性的类型是any
.
function dataFunc<TAttributes extends string>(data: () => Data<TAttributes>): () => Data<TAttributes> {
return data
}
const notOkay = dataFunc(() => ({
attributes: ['firstName'],
initialValues: {
firstName: 'value',
age: 2 // should error out, but it doesn't
},
}))
有没有办法严格执行这一点,或者:
-
部分记录中的精确键(我知道TypeScrip不正式支持这一点,但也许有一种方法可以在这个特定用例中破解它).
-
改进函数参数的推理.我试过用NoInfer技巧来做,但失败了.
-
不允许一条记录中有
any
个值.通常这是通过linting规则和typescript-eslint
插件(例如no-unsafe-return
)来完成的,但没有针对对象值的规则.另外,我希望这是一张打字支票,而不是皮棉支票.