Typescript泛型推断优先考虑参数overs的分配。因为它优先考虑参数,所以即使我将其分配给类型参数设置为对象接口的变量,所有参数道具也将自动转换为类型unknown
。
interface Person {
name: string;
age: number;
id: string;
}
interface Client {
person: Person;
}
class FormField { }
class FormFieldGroup<T> {
constructor(private props: { category: string, questions: FormRelation<Required<T>> }) {}
}
type Primitives = string | number | symbol | bigint | undefined | null;
type FormRelation<T> = {
[K in keyof T]: T[K] extends Primitives ? FormField : FormFieldGroup<T[K]>;
}
abstract class CRUDComponent<D> {
public abstract clientQuestions: FormRelation<D>
}
class ClientComponent extends CRUDComponent<Client> {
public clientQuestions: FormRelation<Client> = {
person: new FormFieldGroup({
category: "Client",
questions: {
name: new FormField(),
age: new FormField(),
id: new FormField(),
}
})
}
}
VScode: Cannot assign FormQuestionGroup<{name: unknown, age: unknown, id: unknown}> to FormQuestionGroup<Person>.
在Java中,菱形运算符会自动推断类型以匹配分配类型参数。但是,出于可读性考虑,Typescript不包括菱形运算符。我正在使用Typescript 3.7,只是想知道是否有解决此错误的方法,而不是指定类型。
另外,当我将props设置为一个空对象时,编译器也可以将Generic推断为正确的接口。
答案 0 :(得分:0)
您可以在T
中为FormQuestionGroup
使用recursive type constraint来对类型进行建模:
// use recursive type constraint for T here
class FormQuestionGroup<T extends FormQuestionGroupProps<T["questions"]>> {
constructor(public props: T) { }
}
interface FormQuestionGroupProps<T> {
questions: FormRelation<T>;
}
type FormRelation<T> = {
[K in keyof T]: FormField;
}
class FormField { }
测试(Playground):
const group = new FormQuestionGroup({
questions: {
name: new FormField(),
age: new FormField()
}
});
group.props.questions.age // FormField, works now
group.props.questions.name // FormField, works now
为什么我们以前得到unknown
类型? TS显然无法正确推断此星座中的T
:
declare function foo<T>(t: { [K in keyof T]: string }): void
foo({ name: "foo", a: "bar" })
// foo<{ name: unknown; a: unknown; }>(t: { name: string; a: string; }): void
PS:我坚持使用您的第3个修订代码示例,该示例仅与推断的unknown
类型有关。最新的代码创建了一个全新的(编译)错误-当您传入T[K] extends Primitives ? FormField : FormFieldGroup<T[K]>
时,FormFieldGroup<T[K]>
始终会解析为FormField
,因为它不是原始的。
答案 1 :(得分:0)
您只需要用type NoInfer<T> = [T][T extends any ? 0 : never]
包装类型即可禁用参数推断。