如何定义具有层次结构泛型和其他字段的 Typescript 接口?

问题描述 投票:0回答:1

我想要什么:

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[]
typescript recursion typescript-generics
1个回答
0
投票

如果您确实希望

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" }

游乐场链接

还有其他方法可以做到这一点,但这是一种相当简单的方法。

© www.soinside.com 2019 - 2024. All rights reserved.