Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/visual-studio-2008/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在TypeScript中按类型查找数组中的值_Typescript - Fatal编程技术网

在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
实例,您可能在当前实现中将
未定义返回为

调用此函数时,可以从第二个参数推断泛型:

查找(动物、狗);

您可以创建一个搜索谓词,而不是创建一个全新的函数。这样,您可以调用vanilla
Array#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);