我遇到了一个关于泛型函数中类型推断的TypeScrip问题.

以下是代码的简化版本:

type FnObj<I extends z.ZodType> = {
    input: I,
    func: (input: I extends z.ZodType<infer U> ? U : never) => void
}

type Objs<I extends z.ZodType = z.ZodType> = {
    [key: string]: FnObj<I>
}

function createFormDef<FF extends Objs>(formObject: FF) {
    return formObject;
}

createFormDef({
    test: {
        input: z.object({
            d: z.number(),
        }),
        func: (input) => {
            input.dsf // This line is not throwing an error, although it should be typed as {d: number}.
        },
    },
});

我已经try 移除Objs的泛型,以使单键成为其自己的类型.但这并没有奏效.如下所示:(还删除了Zod部分)

type FnObj<I extends any = any> = {
    input: I,
    func: (input: I) => void
}

type Objs = {
    [key: string]: FnObj
}

function createFormDef(formObject: Objs) {
    return formObject;
}

createFormDef({
    test: {
        input: {
            hello: 10
        },
        func: (input) => {
            input.dsf // still not working, should typed as {hello:number}
        },
    },
});

推荐答案

TypeScrip不支持existentially quantified generics,所以你不能说"一个属性值为FnObj<I>some I的对象我不在乎".写FnObj<any>(这就是你的FnObj变成你的default type argument)不能做到这一点,因为the any type不安全,所以FnObj<any>允许inputfunc完全不相关的事情.

与其试图编写这样的类型,不如说"我指定的T在键K处的属性值是FnObj<T[K]>的对象".也就是说,您将对对象类型T执行map over操作,以获得相应的Objs<T>:

type Objs<T extends object> = { [K in keyof T]: FnObj<T[K]> }

function createFormDef<T extends object>(formObject: Objs<T>) {
  return formObject;
}

现在,编译器可以从formObject输入推断出T:

const x = createFormDef({
  test: {
    input: {
      hello: 10
    },
    func: (input) => {
      input.dsf // error
    },
  }
});

x.test.input
//     ^?(property) input: { hello: number; }

这里,T被推断为{test: {hello: number}},因此xObjs<T>,即{test: FnObj<{hello: number}>},因此编译器可以将input参数contextually type作为{hello: number}传递给fn回调.

Playground link to code

Typescript相关问答推荐

替代语法/逻辑以避免TS变量被分配之前使用." "

在TypeScript中,除了映射类型之外还使用的`in`二进制运算符?

我用相同的Redux—Toolkit查询同时呈现两个不同的组件,但使用不同的参数

我可以为情态车使用棱角形的路由守卫吗?

等待用户在Angular 函数中输入

分解对象时出现打字错误

限制返回联合的TS函数的返回类型

TypeError:正文不可用-NextJS服务器操作POST

确保对象列表在编译时在类型脚本中具有唯一键

如何将对象数组中的键映射到另一种对象类型的键?

ANGLE订阅要么不更新价值,要么不识别价值变化

TYPE FOR ARRAY,其中每个泛型元素是单独的键类型对,然后在该数组上循环

为什么类型脚本使用接口来声明函数?他的目的是什么.

有没有一种方法可以提升对象的泛型级别,而对象的值是泛型函数?

我如何键入它,以便具有字符串或数字构造函数的数组可以作为字符串或数字键入s或n

带有过滤键的 Typescript 映射类型

使用 fp-ts 时如何使用 TypeScript 序列化任务执行?

递归地排除/省略两种类型之间的公共属性

将 Angular 从 14 升级到 16 后出现环境变量注入问题

如何让 Promise 将它调用的重载函数的类型转发给它自己的调用者?