如何在TypeScript中创建具有受约束的泛型值类型的对象



我知道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"];

还有一个操场。

最新更新