我想要什么:
type LocationBase<Level, LevelName, Child> = ...
type Region = LocationBase<1, "region", Subregion>;
type Subregion = LocationBase<2, "subregion", Area>;
type Area = LocationBase<3, "area">;
相当于:
interface Region {
level: 1;
levelName: "region";
children?: Subregion[];
}
interface Subregion {
level: 2;
levelName: "subregion";
children?: Area[];
}
interface Area {
level: 3;
levelName: "area";
children?: Location<4>;
}
interface Location<T extends number>{
level: T;
levelName: "location";
children?: Location<PlusOne<T>>;
}
这可能吗?
我尝试使用这些代码,但出现了一些错误:
TS2716:类型参数“Child”具有循环默认值。
TS2344:类型“PlusOne
”不满足约束“number”
type ArrayWithLength<Len extends number, Arr extends never[] = []> = Arr["length"] extends Len ? Arr : ArrayWithLength<Len, [never, ...Arr]>;
type PlusOne<T extends number> = [unknown, ...ArrayWithLength<T>]["length"];
interface LocationBase<
Level extends number = number,
LevelName extends string = "location",
Child = LocationBase, // Error
> {
level: Level;
levelName: LevelName;
children?: Child[];
};
type Region = LocationBase<1, "region", Subregion>;
type Subregion = LocationBase<2, "subregion", Area>;
type Area = LocationBase<3, "area", LocationBase<4>>;
// type Level5ArrayExpected = LocationBase<4>["children"]; // unknown[]
如果您确实希望
children
在 Region
和 Subregion
中是可选的,您可以为 Child
提供默认类型 undefined
(这样您可以在指定 Area
时将其保留)并拥有 LocationBase
定义交集类型以包含或不包含 children
:
type LocationBase<Level, LevelName, Child = undefined> =
{
level: Level;
levelName: LevelName;
} & (
Child extends undefined ? {} : {children?: Child[]}
);
那么你的三个例子就可以正常工作了:
type Region = LocationBase<1, "region", Subregion>;
// ^? type Region = { level: 1; levelName: "region"; } & { children?: Subregion[] | undefined; }
type Subregion = LocationBase<2, "subregion", Area>;
// ^? type Subregion = { level: 2; levelName: "subregion"; } & { children?: Area[] | undefined; }
type Area = LocationBase<3, "area">;
// ^? type Area = { level: 3; levelName: "area" }
还有其他方法可以做到这一点,但这是一种相当简单的方法。