我有一个多次调用的函数。
function foo(parameter) {
parameter.a;
parameter.b;
parameter.c;
parameter.d;
}
每个调用的参数都不同,但它们都是所有文字并具有相同的结构。
const first = { a: 1, b: 2, c: 3, c: 4};
const second = { a: 2, b: 4, c: 6, c: 8};
foo(first);
foo(second);
此外,这些对象具有很多属性,因此手动指定参数的类型非常繁琐,这导致了我的问题:如何推断{{1的类型参数?编译器正确地推断出foo
和first
的类型,但似乎无法推断出second
的类型。
这是我尝试过的。
您可以将实例放入类型位置。
parameter
它有效并且类型是正确的,但是我想避免使用这种方法,因为函数和文字是在不同的文件中定义的,我不想将文字导入到文件中功能定义。
如果我将函数转换为lambda,编译器似乎很乐意推断出类型。它看起来像这样:
foo(parameter: typeof first) {
parameter.a;
parameter.b;
//...
}
但是只要我将labmda提取到一个变量中(我需要重用该函数),它就会推断出它。
function wrapper<T>(parameter: T, foo: (p: T) => void) {
foo(parameter);
}
wrapper(first, parameter => { // parameter is inferred to be `typeof first`.
parameter.a;
parameter.b;
//...
})
答案 0 :(得分:1)
我认为接口是你唯一的选择。您可以声明一个虚拟对象,该对象具有您感兴趣的属性,但在当天结束时是等效的。
当您创建这些原始对象时,Typescript正在构建一个隐式接口,其中包含该变量的那些属性。
函数foo
需要它在定义时期望处理的类型信息,以便能够进行充分的类型检查。
您的方法:
这是有效的,因为typeof first为参数提供了隐式构造的接口
{
a:number;
b:number;
c:number;
d:number;
}
所以这些字段在函数中可用。
这也是出于同样的原因,整个包装函数专注于第一个参数的类型(在本例中是first
变量),它是同一个隐式接口。在这种情况下,参数被理解为具有相同的类型,因此可以使用属性a,b,c,d。
lambda的解释方式与解释原始函数定义的方式完全相同,没有关于参数的类型信息。虽然lambda在代码中的包装函数中使用,但不能保证lambda将仅以这种方式使用,因此投影类型信息是不安全的。这也是您的功能失败的原因。
现在有一些语言可以解决这个问题。例如,我认为OCaml可以根据您使用的字段以及范围内的内容智能地隐式确定记录变量的类型。然而,打字稿似乎没有。你必须告诉它你期待的是什么。如果您愿意,可以使用内联接口,但是如果您将接口描述为多长时间,我怀疑这是值得的。
tl; dr:使用明确的界面,它们对你有好处。
答案 1 :(得分:0)
界面怎么样?
interface ILargeObject {
a: number;
b: number;
c: number;
d: number;
}
const first: ILargeObject = { a: 1, b: 2, c: 3, d: 4 };
const second: ILargeObject = { a: 1, b: 2, c: 3, d: 4 };
function foo(parameter: ILargeObject) {
/* ... */
}
然后,您可以将界面导入两个文件。这解决了您必须使用函数定义将文字导入文件的问题。
一个重要的好处是,您的对象类型将在一个位置定义,而不是依赖于单个对象定义的函数参数类型。如果在将来的某个点上改变了这个单独的对象,它将会破坏你的功能。
此方法提供更高的安全性,而且逻辑性和清洁性。