我正在try 围绕react-hook-formregister创建包装函数.我无法从包装器函数将兼容类型传递给register.这个问题并不是专门针对react-hook-form的,而是如何强制执行内部功能参数.

我有示例代码:


interface Child1 {
    p1: string;
}

interface Child2 {
    p2: number
}

interface Parent {
    child1: Child1;
    child2: Child2
}

function register(o: "child1.p1" | "child2.p2") {return {}}

function getChildRegister(parent: Parent, parentKey: keyof Parent) {
    return function(childKey: keyof Parent[typeof parentKey]) {
        return register(`${parentKey}.${childKey}`)
    }
}

const p: Parent = {child1: {p1: ""}, child2: {p2: 1}}

const result = getChildRegister(p, "child1")("p1") // error! inner function param is not inferred for some reason

我将child1传递到getChildRegister,并期望内部函数参数接受Child1个键(本例中为p1个).但由于某种原因,Typescript 只接受string.如何让内部函数接受子类型键?

Typescript Playground Link

提前感谢!

推荐答案

您的函数具有以下调用签名:

function getChildRegister(
  parent: Parent, parentKey: keyof Parent
): (childKey: never) => {}

问题是getChildRegister()不是generic.它甚至没有try 跟踪parentKey中的特定literal type. 仅仅写typeof parentKey并不能改变这一点;这相当于只有keyof Parent.

然后keyof Parent[typeof parentKey]只是keyof (Parent[keyof Parent]),由于Parent[keyof Parent]union type {p1: string} | {p2: number},因此keyof operator返回the never type,因为unions 成员没有共同的 keys .

如果您希望返回的函数确切地关心parentKey传递的值,则需要整个事情都是通用的,如下所示:

function getChildRegister<K extends keyof Parent>(
  parent: Parent, parentKey: K
): (childKey: keyof Parent[K]) => {}

现在parentKey属于K constrainedkeyof Parent的通用类型. 当您调用getChildRegister()时,您为parentKey传递的特定值将导致编译器推断K的文字类型,然后返回的函数将期望keyof Parent[K],这取决于K:

getChildRegister(p, "child1")("p1") // okay
getChildRegister(p, "child1")("p2") // error
getChildRegister(p, "child2")("p1") // error
getChildRegister(p, "child2")("p2") // okay

看起来不错


您可以这样实现该功能:

function getChildRegister<K extends keyof Parent>(parent: Parent, parentKey: K) {
    return function(childKey: keyof Parent[K]) {
        return register(`${parentKey}.${childKey as any}` as any) 
    }
}

但请注意,register(`${parentKey}.${childKey}`)将不再单独工作,因为现在childKeyparentKey的关系更复杂,编译器无法遵循它.在上面的内容中,我使用了一些assertionsthe intentionally loose any type来避免编译器错误.这个问题无法研究如何输入内容以便编译器能够遵循您的逻辑,所以我就把它留在那里.

Playground link to code

Typescript相关问答推荐

如何在另一个if条件中添加if条件

类型脚本不会推断键的值类型

如何从TypScript中的接口中正确获取特定键类型的所有属性?

为什么缩小封闭内部不适用于属性对象,但适用于声明的变量?

VS代码1.88.0中未出现自动导入建议

在Angular中,如何在文件上传后清除文件上传文本框

如何创建泛型类型组件来使用React Native的FlatList或SectionList?'

泛型类型联合将参数转换为Never

如何根据特定操作隐藏按钮

打印脚本中的动态函数重载

打字类型保护递归判断

在分配给类型的只读变量中维护const的类型

迭代通过具有泛型值的映射类型记录

为什么Typescript不能推断类型?

React router 6(数据路由)使用数据重定向

如何按属性或数字数组汇总对象数组

如何静态键入返回数组1到n的函数

如何在TypeScrip中使用数组作为字符串的封闭列表?

对象只能使用 Typescript 中另一个对象的键

当受其他参数限制时,通用参数类型不会缩小