我知道TypeScript中的键/值对象是这样键入的:
const animals: { [key: string]: string } = { a1: "cat", a2: "dog" };
上面的对象只允许字符串类型的值。
现在,假设我有一个抽象类
abstract class Animal {
abstract makeSound(): void;
move(): void {
console.log("roaming the earth...");
}
}
如何使animals
对象只能有实际的动物,即扩展Animal
的类(而不是实例(?
我试过这个,但得到了";找不到名称"T";作为错误。
const animals: { [key: string]: T extends typeof Animal } = { a1: Cat, a2: Dog };
const animal = new animals["a2"]();
也试过这个,但得到了"?"预期的";
const animals: { [key: string]: any extends typeof Animal } = { a1: Cat, a2: Dog };
const animal = new animals["a2"]();
如果我事先知道所有类型的动物(但我不知道(,这会起作用:
const animals: { [key: string]: typeof Cat | typeof Dog } = { a1: Cat, a2: Dog };
const animal = new animals["a2"]();
有没有办法使其通用?
根据上面的评论,OP似乎在问是否可以创建一个所有扩展Animals的类的映射(而不是Animal实例的映射(。这可以使用函数和泛型来完成,就像这样[编辑以解决下面的评论]:
abstract class Animal {
abstract makeSound(): void;
move(): void {
console.log("roaming the earth...");
}
}
class Cat extends Animal {
makeSound(){console.log("meow")}
}
class Dog extends Animal {
makeSound(){console.log("woof")}
}
class Tiger extends Animal {
makeSound(){console.log(“roar”)}
}
function addToAnimals<T extends Record<string, typeof Animal>, U extends Record<string, type of Animal>(animals: T | {}, newAnimal: U){
return {...animals, ...newAnimal}
}
const animals = addToAnimals({}, {a :Dog, b: Cat})
const animals2 = addToAnimals(animals, {c: Tiger})
const animal = new animals["a"]();
const animal2 = new animals2[“c”]();
这里的游乐场
其基本思想是,creator函数接受带有约束<T extends Record<string, typeof Animal>>
的新扩展类,这确保您只给它Animals。但是TS随后从参数中推断出实际的类值,并在构建新的动物对象时使用它。
在写评论时,我没有注意到抽象的东西,很抱歉。
不管怎样,我认为不可能做你想做的事。基本上,你的问题可以归结为";有没有一种方法可以创建一个类型,包括给定类的所有非抽象的子类&";,要做到这一点,给定一个类,您需要检查它是否抽象,这是不可能的。因此,正如我所看到的,你唯一的选择就是要么使Animal
不抽象,要么在这个地方不使用类型。
此外,如果Animal
是抽象的,typeof
也不起作用,因为假设您找到了一种方法来生成类型ChildrenOf<T>
,它包括类的所有子级,但不包括类本身。如果Animal
是正常的,那没关系,但如果Animal
是抽象的,那么你可以这样做:
abstract class Mammal extends Animal {}
const a: ChildrenOf<Animal> = Mammal
new a()
这里Mammal
可以分配给ChildrenOf<Animal>
,因为它是一个子,但它是抽象的,所以不应该被实例化。如果Animal
正常,则不会出现此问题,因为Mammal
不可分配给typeof Animal
这里发生了一些事情。对于你的主要问题,当你定义一个抽象类(或者任何类(时,你也在用typescript定义一个类型。因此,要将一个类型限制为该类,例如Animal,只需使用它的名称即可。所以[key:string]: Animal
这里还有一些其他问题,即在不调用构造函数的情况下实例化Cat和Dog,然后用构造函数实例化数组。以下是我认为你想要的清理后的代码:
abstract class Animal {
abstract makeSound(): void;
move(): void {
console.log("roaming the earth...");
}
}
class Cat extends Animal {
makeSound(){console.log("meow")}
}
class Dog extends Animal {
makeSound(){console.log("woof")}
}
const animals: { [key: string]: Animal } = { a1: new Cat, a2: new Dog };
const animal = animals["a2"];
还有一个操场。