在TypeScript中按类型查找数组中的值
我正在尝试构建一种方法,用于按类型查找数组中的项。考虑这个特殊的设置:在TypeScript中按类型查找数组中的值,typescript,Typescript,我正在尝试构建一种方法,用于按类型查找数组中的项。考虑这个特殊的设置: 抽象类动物{} 类狗扩展动物{} 类Cat扩展了动物{} 马类动物{} 常数动物:动物[]=[新狗、新猫、新马]; 我正在尝试编写一个函数,可以从animals中按类型查找元素,比如:findAnimal(animals)。用通俗易懂的英语:“找到动物的第一个元素,它是狗的一个实例。下面是它的一个粗略的示意图: 函数查找(项目:动物[]):A{ 返回项目。查找((a:Animal)=>a的实例)作为; } 这不会编译,我
抽象类动物{}
类狗扩展动物{}
类Cat扩展了动物{}
马类动物{}
常数动物:动物[]=[新狗、新猫、新马];
我正在尝试编写一个函数,可以从animals
中按类型查找元素,比如:findAnimal(animals)
。用通俗易懂的英语:“找到动物的第一个元素,它是狗的一个实例。下面是它的一个粗略的示意图:
函数查找(项目:动物[]):A{
返回项目。查找((a:Animal)=>a的实例)作为;
}
这不会编译,我理解为什么:编译后,泛型参数不再存在。然而,有没有办法让这样的东西发挥作用?我当然同意将函数修改为两个参数:
function find(items: Animal[], A: NOT_SURE_WHAT_GOES_HERE): WHAT_TO_RETURN {
// ...
}
但是,有了这个更改,我不知道如何正确指定第二个参数或返回类型。我的选项是什么?您可以在类参数的类型和返回值中使用泛型,如下所示:
函数find作为find
回调函数的返回值,我们不再需要类型断言。这更安全-您可能在animals
中找不到cls
实例,您可能在当前实现中将未定义返回为
调用此函数时,可以从第二个参数推断泛型:
查找(动物、狗);
您可以创建一个搜索谓词,而不是创建一个全新的函数。这样,您可以调用vanillaArray#find
方法,但也可以确保返回正确的类型:
abstract class Animal {}
class Dog extends Animal { bark() {} }
class Cat extends Animal { meow() {} }
class Horse extends Animal { neigh() {}}
const animals: Animal[] = [new Dog, new Cat, new Horse];
const animal = animals.find((item: Animal): item is Dog => item instanceof Dog);
if (animal) { //make sure it's not `undefined`
animal.meow(); //Error - it's not a Cat
animal.neigh(); //Error - it's not a Horse
animal.bark(); //OK - it's a Dog
}
然后可以将其推广,并使其易于作为通用函数重用:
abstract class Animal {}
class Dog extends Animal { bark() {} }
class Cat extends Animal { meow() {} }
class Horse extends Animal { neigh() {}}
const animals: Animal[] = [new Dog, new Cat, new Horse];
const search = <A extends Animal>(species: new() => A) => (item: Animal): item is A =>
item instanceof species;
const animal = animals.find(search(Dog));
if (animal) { //make sure it's not `undefined`
animal.meow(); //Error - it's not a Cat
animal.neigh(); //Error - it's not a Horse
animal.bark(); //OK - it's a Dog
}
此函数可以进一步推广到任何超/子类关系,并允许任何可变构造函数。请注意,您的接口[不应为空][https://github.com/microsoft/TypeScript/wiki/FAQ#why-是否所有类型都可分配给空接口):
不设置Super
泛型参数,因此将其设置为unknown
。如果要派生谓词并设置类型,则需要
const searchDog = search<Animal, Dog>(Dog);
const searchDog=搜索(Dog);
您必须将类作为参数传递,而不是泛型;find(animals,Dog)
,它的类型将是typeof Animal
。但是您如何指定返回类型呢?这就成功了!不过,对于未来的读者来说:如果Dog
接受构造函数参数,您需要澄清一点:cls:new(…args:any[])=>A
以使其正常工作。否则编译器将失败,出现如下神秘消息:“typeof Dog不可分配给new()=>Dog”@ChipBell是的,构造签名必须与实际构造的内容相匹配,您基本上将调用new Thing(arg1,arg2)
重新安排为签名new(arg1:Type1,arg2:Type2)=>事物
。
abstract class Animal { isPet?: boolean }
class Dog extends Animal { bark() {} }
class Cat extends Animal { constructor(name: string) {super(); } meow() {} }
class Horse extends Animal { constructor(age: number, recehorse: boolean) {super();} neigh() {}}
declare const animals: Animal[];
const search = <Super, Child extends Super>(specific: new(...args: any[]) => Child) => (item: Super): item is Child =>
item instanceof specific;
const dog = animals.find(search(Dog)); //OK
const cat = animals.find(search(Cat)); //OK
const horse = animals.find(search(Horse)); //OK
const dogs = animals.filter(search(Dog)); //OK
if (animals.every(search(Dog))) { } //OK
animals.find(search(String)); // Error - String is not assignable to Animal
declare const cats: Cat[];
cats.find(search(Dog)); //Error - Dog is not a assignable to Cat
const searchDog = search(Dog);
const searchDog = search<Animal, Dog>(Dog);