道歉的标题,因为我不知道如何清楚地表达。
我正在尝试找到一种创建通用类型的方法,该方法稍后将用于传递通用类型。
要消除混乱,请考虑以下两个界面:
interface Field<T> {
value: T;
hasError: boolean;
}
interface Record {
id: number;
name: string;
}
Field
的这些继承
interface FooField<T> extends Field<T> {
foo: () => void;
}
interface BarField<T> extends Field<T> {
bar: () => void;
}
我想生成以下类型的Record
的新类型:
interface FooRecord {
id: FooField<number>;
name: FooField<string>;
}
interface BarRecord {
id: BarField<number>;
name: BarField<string>;
}
最直观但不正确的方法如下:
type MagicRecord<XField extends Field> = {
[K in keyof Record]: XField<Record[K]>;
};
type FooRecord = MagicRecord<FooField>;
type BarRecord = MagicRecord<BarField>;
即使可能,我该如何正确使用打字稿?
答案 0 :(得分:0)
您需要higher kinded types,从v3.5开始,TypeScript不支持。您在这里所做的任何事情都将是一种变通办法,其中涉及大量的代码重复。
这是一种可能的解决方法。首先,请注意,我不会使用名称Record
,因为它会与built-in type alias的名称冲突。我将切换到MyRecord
:
interface MyRecord {
id: number;
name: string;
}
因此,我们有一个查找表FieldLookup<T>
,它从通用类型的名称映射到由T
指定的通用类型本身。您要支持的Field<T>
的每种子类型都需要一个表:
interface FieldLookup<T> extends Record<keyof FieldLookup<any>, Field<T>> {
Field: Field<T>;
FooField: FooField<T>;
BarField: BarField<T>;
}
然后我们可以定义MagicRecord<XField>
,它将通用字段的名称作为字符串文字:
type MagicRecord<XField extends keyof FieldLookup<any>> = {
[K in keyof MyRecord]: FieldLookup<MyRecord[K]>[XField]
};
type FooRecord = MagicRecord<"FooField">;
type BarRecord = MagicRecord<"BarField">;
所以可行。通过对FieldLookup
进行反向查找,我们可以做得更进一步,以使您无需使用或关心类型名称:
type ReverseLookup<F extends Field<any>> = {
[K in keyof FieldLookup<any>]: FieldLookup<any>[K] extends F ? K : never
}[keyof FieldLookup<any>];
然后MagicRecord<XField>
将用作您的原始版本,除了XField
必须是具体类型:
type MagicRecord2<XField extends Field<any>> = MagicRecord<
ReverseLookup<XField>
>;
type FooRecord2 = MagicRecord2<FooField<any>>; // FooField<any>, not FooField
type BarRecord2 = MagicRecord2<BarField<any>>; // BarField<any>, not BarField
这也可以。
好的,希望能有所帮助。祝你好运!