我试图从另一个对象属性推断一个对象属性的类型。
type Dog = { name: string };
type Cat = { age: number};
class AnimalType<T> {
}
class AnimalTypeRegistry {
static Dog: AnimalType<Dog>
static Cat: AnimalType<Cat>
}
interface IConfig<T> {
type: AnimalType<T>;
init: Partial<T>;
}
class Config {
get list(): IConfig<any>[] {
return [
{
type: AnimalTypeRegistry.Dog,
init: {
name: 'Bob' // Note - intellisense does not know this exists.
}
},
{
type: AnimalTypeRegistry.Cat,
init: {
age: 3 // Note - intellisense does not know this exists.
}
}
]
}
}
我希望intellisense能够将init推断为Dog类型,并且name属性存在。而是默认为任何(由于函数返回类型)。
答案 0 :(得分:1)
如果您使用IConfig<any>
,则会丢失所有类型提示,因为any
可能是任何东西。
如果您希望对类型进行足够的区分以获取有意义的IntelliSense,则有助于固定union的这些类型...尤其是discriminated union:
// Use a discriminated union for types
type Dog = { name: string; kind: "Dog" };
type Cat = { age: number; kind: "Cat" };
type Animal = Dog | Cat;
在这里,Animal
是有区别的联合:discriminant属性称为kind
,您可以使用字符串文字值"Dog"
和"Cat"
来区别你拥有工会。
暂时不在代码中使用“注册表”和“ AnimalType<T>
”(如果以后需要,您可以自己获得此功能),我将IConfig<K>
依赖于{{1所讨论的kind
的}}属性K
:
Animal
请注意,// have IConfig<K> depend on the discriminant K
interface IConfig<K extends Animal["kind"]> {
type: K;
init: Partial<Extract<Animal, { kind: K }>>;
}
属性是init
。 Partial<Extract<Animal, {kind: K}>>
对您很有意义,但是Partial
用于extract Extract<Animal, {kind: K}>
属性为Animal
的{{1}}联合的特定成员。 / p>
然后您要kind
输出一个K
元素的数组。您可以通过编程方式从list()
生成该类型,如下所示:
IConfig<"Dog"> | IConfig<"Cat">
请注意,您不要要Animal
(联合位于另一个位置),因为这些将允许像// SomeConfig is the union of all possible IConfig<K> types
type SomeConfig = { [K in Animal["kind"]]: IConfig<K> }[Animal["kind"]];
// type SomeConfig = IConfig<"Dog"> | IConfig<"Cat">
这样的合并元素,我认为您不需要不想。
最后,您获得了想要的IntelliSense:
IConfig<"Dog" | "Cat">
好的,希望能有所帮助。祝你好运!