typescript - 预期 3 个类型参数,但得到 1 个,但它应该推断出 2 个类型
问题描述
我想知道如何正确推断我的函数的第二个和第三个模板
假设一个简单的界面
interface ISome {
a: string;
b?: {
c: string;
};
}
关注作品
function pathBuilder<
K1 extends keyof ISome,
K2 extends keyof NonNullable<ISome[K1]>>(p: K1, p2?: K2) {
let res = String(p);
if (p2) { res += "." + p2; }
return res;
}
const pathTest = pathBuilder("b", "c"); // ---> "b.c" and intellisense works on parameters
但我需要通过指定另一种类型来概括该函数的工作(我不想传递对象实例来指定类型)
所以,以下不起作用
function pathBuilder<
T,
K1 extends keyof T,
K2 extends keyof NonNullable<T[K1]>>(p: K1, p2?: K2) {
let res = String(p);
if (p2) { res += "." + p2; }
return res;
}
const pathTest = pathBuilder<ISome>("b", "c"); // ERROR: Expected 3 type arguments, but got 1.ts(2558)
似乎函数的第二个和第三个模板参数不是从第一个参数推断出来的,但它应该是因为在第一种情况下,当我直接指定类型 T=ISome 时它起作用了。
我不确定是否有一些语言关键字可以使其工作,但模板应该完全适用:指定未知类型。
编辑
实际上我找到了这种方式,但需要额外的编码,如果可能的话我会避免
function pathBuilder<T>() {
return <
K1 extends keyof T,
K2 extends keyof NonNullable<T[K1]>>(p: K1, p2?: K2) => {
let res = String(p);
if (p2) { res += "." + p2; }
return res;
};
}
const pathTest = pathBuilder<ISome>()("b", "c");
解决方案
从 TS3.4 开始,没有部分类型参数推断。要么让编译器尝试推断所有类型参数,要么指定所有类型参数。(嗯,有默认类型参数,但这并没有给你你想要的:你想推断你遗漏的类型参数,而不是为它们分配默认类型)。已经有几个提议来解决这个问题,但迄今为止没有一个得到完全批准。
因此,目前只有解决方法。我能想到的两个是使用虚拟函数参数或使用currying。
虚拟参数版本:
function pathBuilderDummy<
T,
K1 extends keyof T,
K2 extends keyof NonNullable<T[K1]>>(dummy: T, p: K1, p2?: K2) {
let res = String(p);
if (p2) { res += "." + p2; }
return res;
}
const pathDummyTest = pathBuilderDummy(null! as ISome, "b", "c");
在这里,我们正在做你说你不想做的事情......传入一个 type 的参数T
。但是由于它只是一个虚拟参数并且在运行时不使用,所以它只关心类型系统认为它是什么。您传入的值的实际类型无关紧要。所以你可以通过它null
并使用类型断言来选择T
。
柯里化函数解决方案:
const pathBuilderCurry =
<T>() => <
K1 extends keyof T,
K2 extends keyof NonNullable<T[K1]>>(p: K1, p2?: K2) => {
let res = String(p);
if (p2) { res += "." + p2; }
return res;
}
const pathCurryTest = pathBuilderCurry<ISome>()("b", "c")
在这里,您将返回一个返回另一个函数的函数。第一个函数不接受值参数,但它确实接受您要指定的一个类型参数。然后它返回一个指定的函数,T
但推断其他类型参数。
这两种解决方案都不是完美的,但它们是我们目前能做的最好的。希望有帮助;祝你好运!
推荐阅读
- pandas - 新列中的组计数
- excel - How can I convert a number in a cell to time format when sending this cell via email?
- php - PHP 打印 - 调用未定义的函数 printer_list()
- electron - 为什么 Electron-Angular 项目在构建时会出现 GL ERROR
- node.js - 使用 nodejs 包装时,Cypress.io 找不到规范
- javascript - 如何在数组中对数组的第二个值进行排序?
- c# - 语音识别语义解释 UWP
- javascript - 将 2D SDF 函数转换为 JavaScript
- php - 如何将 Varnish ESI 与模块化 PHP 模板系统一起使用
- ios - 经常重新计算路线的问题