打字稿泛型:从函数参数的类型推断类型?
Typescript generics: infer type from the type of function arguments?
我有一个有 2 个参数的方法,我希望它从第一个参数推断出一个类型。
例如,在下面的代码中,我希望从 firstArgument
推断出函数 create_C<T>
的类型 T
,以便 return 类型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
的 return 类型不是 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
的 return 类型不是 B
类型?
这是 Stackblitz 编辑 link:https://stackblitz.com/edit/qqddsn
这是由于 secondArgument: (obj: any) => T
。
如果将上述定义应用于 () => ({ prop2: 2 })
T
的类型是 { prop2: number }
。您可以将其更改为其他内容以获得所需的结果。
例如。
interface C<T> {
firstArgument: A<T>;
secondArgument: (obj: any) => any;
}
export interface A<T> {
type: T;
}
declare function create_C<T>(
firstArgument: A<T>,
secondArgument: (obj: any) => any
): C<T>;
interface B {
prop1: string;
prop2: number;
}
export class B_Component implements A<B> {
type: B;
configuration: B = {
prop1: "",
prop2: 1
};
}
const b = new B_Component();
export const c = create_C(b, () => ({ prop2: 2 }));
在你的函数签名中
declare function create_C<T>(a1: A<T>, a2: (obj: any) => T): C<T>;
T
有两个推理位点("inference site" 表示 "someplace the compiler can use to try to infer a type for a type parameter")。一个站点来自第一个参数a1
的type
属性,另一个站点是第二个参数a2
的return类型。编译器查看像
这样的调用
create_C(new B_Component(), () => ({ prop2: 2 });
并尝试从两个站点推断 T
。在这种情况下,有一个匹配项:(new B_Component()).type
和 {prop2: 2}
都可以分配给 {prop2: number}
。所以没有错误,你得到 C<{prop2: number>
出来。在另一种情况下,这可能正是您希望编译器实现的行为。
相反,您希望看到编译器仅使用 a1
来推断 T
,并仅验证 a2
是否匹配它。也就是说,您希望 (obj: any) => T
中的 T
成为 non-inferential type parameter (see microsoft/TypeScript#14829)。不幸的是,没有 "official" 对此的支持。但幸运的是,通常可以使用变通技术来获得此行为。
这是一种这样的技术:如果您将推理站点中的类型参数从 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>
类型的输出。
好的,希望对您有所帮助;祝你好运!
我有一个有 2 个参数的方法,我希望它从第一个参数推断出一个类型。
例如,在下面的代码中,我希望从 firstArgument
推断出函数 create_C<T>
的类型 T
,以便 return 类型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
的 return 类型不是 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
的 return 类型不是 B
类型?
这是 Stackblitz 编辑 link:https://stackblitz.com/edit/qqddsn
这是由于 secondArgument: (obj: any) => T
。
如果将上述定义应用于 () => ({ prop2: 2 })
T
的类型是 { prop2: number }
。您可以将其更改为其他内容以获得所需的结果。
例如。
interface C<T> {
firstArgument: A<T>;
secondArgument: (obj: any) => any;
}
export interface A<T> {
type: T;
}
declare function create_C<T>(
firstArgument: A<T>,
secondArgument: (obj: any) => any
): C<T>;
interface B {
prop1: string;
prop2: number;
}
export class B_Component implements A<B> {
type: B;
configuration: B = {
prop1: "",
prop2: 1
};
}
const b = new B_Component();
export const c = create_C(b, () => ({ prop2: 2 }));
在你的函数签名中
declare function create_C<T>(a1: A<T>, a2: (obj: any) => T): C<T>;
T
有两个推理位点("inference site" 表示 "someplace the compiler can use to try to infer a type for a type parameter")。一个站点来自第一个参数a1
的type
属性,另一个站点是第二个参数a2
的return类型。编译器查看像
create_C(new B_Component(), () => ({ prop2: 2 });
并尝试从两个站点推断 T
。在这种情况下,有一个匹配项:(new B_Component()).type
和 {prop2: 2}
都可以分配给 {prop2: number}
。所以没有错误,你得到 C<{prop2: number>
出来。在另一种情况下,这可能正是您希望编译器实现的行为。
相反,您希望看到编译器仅使用 a1
来推断 T
,并仅验证 a2
是否匹配它。也就是说,您希望 (obj: any) => T
中的 T
成为 non-inferential type parameter (see microsoft/TypeScript#14829)。不幸的是,没有 "official" 对此的支持。但幸运的是,通常可以使用变通技术来获得此行为。
这是一种这样的技术:如果您将推理站点中的类型参数从 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>
类型的输出。
好的,希望对您有所帮助;祝你好运!