【发布时间】:2022-10-05 04:13:45
【问题描述】:
我在我的代码库中创建了以下 util 函数:
const pick = <T extends object, P extends keyof T, R = Pick<T,P>>(
obj: T,
keys: P[]
): R => {
if (!obj) return {} as R
return keys.reduce((acc, key) => {
return {...acc, [key]:obj[key] };
}, {} as R)
};
该函数工作正常,并且 TS 推断出正确的返回类型。唯一的问题是 keys 参数,我想根据之前选择的键来限制它。
例子:
const obj = {name: 'John Doe', age: '33', city: 'NYC'}
// When typing the keys in the keys array param, it infers the keys correctly
const a = pick(obj, ['name', 'age'])
// BUT, this is also possible, and TS doesnt complain
const b = pick(obj, ['name', 'age', 'age'])
// ALSO, when I have already entered for example 'name', I want intellisense only to show 'age' and 'city' as possible options, currently it still shows all keys.
我尝试了很多东西(甚至对函数进行了柯里化),但没有成功,事实证明这是一个艰难的 TS 难题。我希望我能得到一些帮助!
【问题讨论】:
-
您的
R类型参数是多余的,出于您的问题的目的,可能应该用Pick<T, P>替换......即使您想使用通用默认值作为速记,它也可能超出了所问问题的范围。 -
你能解释一下你为什么关心这个吗?
pick(obj, ["name", "age", "age"])有问题吗?输出是否以某种方式出乎意料? -
请注意,您可以获得您想要的行为,如this playground example 所示,但对于看似可疑的好处来说,这非常复杂。如果你愿意,我可以把这个解决方案写成答案......除非有什么对你不起作用的东西。让我知道。
-
@jcalz 感谢您的回答,它肯定更接近我想要的。唯一剩下的是智能感知,你可以在这里看到它:LINK,名字已经被选中,所以它不应该是一个选项。所以对于下一个可选择的键,我只想看到:[年龄,城市]。我知道它矫枉过正,输出并不意外,但我喜欢智能感知是对仍然可能的事情的反映,而不是所有可能性。如果那有意义的话。我很想写下你的解决方案。我非常感谢您的努力。这让我很头疼
-
我认为不可能让 IntelliSense 自动完成提示执行您想要的操作,因为据我所知,它从约束
K extends Array<keyof T>获取该列表...约束必须是K extends ExcludeArray<keyof T, K>才能给您IntelliSense,但该约束是非法循环的。您仍然希望将答案写下来还是 IntelliSense 提示更重要?
标签: javascript typescript function