起初,我有一个这样的类型:
type Foo = {
bar: string;
children: Foo[];
};
现在,我想允许扩展Foo
类型,以便用户可以添加属性,但仍至少提供bar
和children
。我认为我可以轻松做到这一点:
interface Foo<T extends Foo<T>> {
bar: string;
children: T[];
}
这是一个无限循环...
因此,我然后尝试使用默认的泛型类型参数,但是再次,我无法...
我要放屁吗?还是不可行?
我试图传达:
Foo
是可扩展的Foo
具有与类型本身相同类型的children
属性any
在任何地方都没有-双关语意味)
答案 0 :(得分:1)
取决于您想要扩展Foo类型的方式。如果要临时添加和访问属性(在代码中的任何时候),Foo的界面中必须具有“字符串索引签名”:
type Foo = {
bar: string;
children: Foo[];
[key: string]: any; };
let fooInstance: Foo;
fooInstance.bar = "toto";
fooInstance.newProperty = 24;
Vscode图片:
您还可以通过继承使用其他接口扩展Foo。
interface FooExtended extends Foo {
age: number;
street: string;
}
let extendedFoo : FooExtended;
extendedFoo.age = 22;
extendedFoo.bar = "popo";
您可以覆盖该接口,以将children数组与新接口进行匹配:
interface FooExtended extends Foo {
age: number;
street: string;
children: FooExtended[];
}
答案 1 :(得分:1)
您可以添加空接口JustFoo
来避免无限循环:
interface Foo<T> {
bar: string;
children: T[];
}
interface JustFoo extends Foo<JustFoo> {
}
interface Bar extends Foo<Bar> {
barProp: number;
}
const bar: Bar = {
barProp: 123,
bar: 'aaa',
children: [{ barProp: 123, bar: 'aaa', children: []}]
}
const foo: JustFoo = {
bar: 'aaa',
children: [{ bar: 'aaa', children: []}]
}
答案 2 :(得分:0)
好的, 感谢Lombas和aquz为我指出正确的方向。像以前一样,我试图简化我的问题以便在这里共享,而这样做却过于简化了。
我更准确的问题是以下结构:
export type NavigationEntry = NavigationEntryWithChildren | NavigationEntryWithoutChildren;
interface NavigationEntryBase {
display: string;
exact?: boolean;
}
interface NavigationEntryWithChildren extends NavigationEntryBase {
children: NavigationEntry[];
}
interface NavigationEntryWithoutChildren extends NavigationEntryBase {
routerLinkInfo: any[] | string;
}
顾名思义,这是关于创建导航结构的。在任何级别上,您都有一个URL(routerLinkInfo
),或者您有孩子。因此,我不得不使用 union 类型,而不仅仅是接口。
尽管我已经全职从事TypeScript三年了,但我的头脑有时还是陷在更传统的面向对象的类型系统(如C#)中,而忘记了TypeScript会使其正常工作。
>因此,我没有摆弄NavigationEntry
并使其直接工作,而是创建了两个额外的类型:
interface CustomNavigationEntryWithChildren<T> extends NavigationEntryWithChildren {
children: CustomNavigationEntry<T>[];
}
export type CustomNavigationEntry<T> =
| (CustomNavigationEntryWithChildren<T> & T)
| (NavigationEntryWithoutChildren & T);
使用这种方法,只需要NavigationEntry
的所有现有代码仍然可以使用。想要在其导航节点上添加额外属性的较新项目可以做到这一点:
type Foo = CustomNavigationEntry<{foo: boolean}>;
以上内容将要求所有节点都具有foo
布尔值。
希望这有助于下一个人(即使只是我自己;))