我有一个有 2 个参数的方法,我希望它从第一个参数推断一个类型。
例如,在下面的代码中,我想要类型 T
功能create_C<T>
从 firstArgument
推断所以返回类型为 create_C
函数将是 C<type inferred from firstArgument>
interface C<T> {
firstArgument: A<T>;
secondArgument: (obj: any) => T
}
export interface A<T> {
type: T;
}
function create_C<T>(
firstArgument: A<T>,
secondArgument: (obj: any) => T
): C<T> {
return {
firstArgument,
secondArgument
}
}
但是,在下面的实现中,
const c
的类型被推断为 C<{ prop2: number }>
.但我希望它被推断为 C<B>
我希望编译器抛出一个错误,指出 secondArgument
的返回类型不是类型 B
interface B {
prop1: string;
prop2: number
}
export class B_Component implements A<B> {
type: B = {
prop1: "",
prop2: 1
};
}
const c = create_C(
new B_Component(),
() => ({ prop2: 2 })
)
我如何确保编译器抛出错误,指出
secondArgument
的返回类型不是类型 B
?这是 Stackblitz 编辑器链接:https://stackblitz.com/edit/qqddsn
最佳答案
在您的函数签名中
declare function create_C<T>(a1: A<T>, a2: (obj: any) => T): C<T>;
T
有两个推理站点(“推理站点”的意思是“编译器可以用来尝试推断类型参数的类型的某个地方”)。一个站点来自 type
第一个参数的属性 a1
,另一个站点是第二个参数的返回类型a2
.编译器看起来像这样的调用create_C(new B_Component(), () => ({ prop2: 2 });
并试图推断
T
从两个站点。在这种情况下,有一个匹配项:both (new B_Component()).type
和 {prop2: 2}
可分配给 {prop2: number}
.所以没有错误,你会得到 C<{prop2: number>
出来。在另一种情况下,这可能正是您想要的编译器行为。相反,您希望看到编译器仅使用
a1
推断 T
, 并验证 a2
匹配它。也就是说,您想要 T
在 (obj: any) => T
成为 non-inferential type parameter (see microsoft/TypeScript#14829) .不幸的是,对此没有“官方”支持。但幸运的是,有一些解决方法通常可用于获得这种行为。这是一种这样的技术:如果您从
T
更改推理站点中的类型参数至 T & {}
,它lowers the site's priority .所以编译器会倾向于推断 T
首先从其他推理站点返回 T & {}
一个如果它无法从其他地方推断出来。和类型T & {}
与 T
非常相似(如果 T
是一个对象类型,那么它基本上是相同的)所以它不会改变太多语义。让我们试试看:declare function create_C_better<T>(a: A<T>, b: (obj: any) => T & {}): C<T>;
开始:
const c2 = create_C_better(
new B_Component(),
() => ({ prop2: 2 }) // error!
// ~~~~~~~~~~~~~~ <-- prop1 is missing
)
const c3 = create_C_better(
new B_Component(),
() => ({ prop1: "all right", prop2: 2 })
); // C<B>
在那里,当
prop1
时你会得到你想要的错误丢失,当你修复它时,你会得到类型 C<B>
的输出如预期的。好的,希望有帮助;祝你好运!
Link to code
关于 typescript 泛型 : infer type from the type of function arguments?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59055154/