我正在try 向函数添加类型,该函数将类型化对象数组作为参数,并返回另一种类型的映射数组:

const createAnimals = <T extends AnimalFactory<any>[]>(factories: T) => {
  return factories.map((f) => f());
};

一旦正确键入此函数,它将抛出一个错误,错误代码如下:

const factories = [() => new Dog(), () => new Cat()];
const animals = createAnimals(factories);

// ❌ should fail !
animals[0].meow();

我想让编译器知道animals[Dog, Cat]类型的.

我一直在try 使用infer,但迄今为止没有成功.

推荐答案

这样做是可能的,但解决方案将要求您以只读方式键入factories,否则该类型将根本不包含足够的信息.

const factories = [() => new Dog(), () => new Cat()] as const;

如果你为这样的工厂声明了一个类型(这已经不是关于动物的了,但让我们坚持下go )

type AnimalFactory<T> = () => T

您可以创建一个映射类型,该类型采用AnimalFactory的元组,并生成相应动物类型的元组:

type FactoryAnimals<T extends AnimalFactory<unknown>[]> =
  {[K in keyof T]: T[K] extends AnimalFactory<infer A> ? A : never}

现在,您可以使用AnimalFactory作为createAnimals的返回类型:

const createAnimals = <T extends AnimalFactory<unknown>[]>
  (factories: readonly [...T]) => factories.map(f => f()) as FactoryAnimals<T>;

不幸的是,as FactoryAnimals<T>断言是必需的,因为TypeScript无法推断对元组进行映射会产生映射类型.readonly [...T]位是为了避免只读T,这将导致只读返回类型,并需要额外的断言.

如果在工厂中调用createAnimals,它将生成所需类型的元组:

const animals = createAnimals(factories);
// type: [Dog, Cat]

// ❌ should fail !
animals[0].meow(); // Error: Property 'meow' does not exist on type 'Dog'.

如果用显式数组而不是变量来调用它,可以省go as const,因为[...T]类型导致factories被视为元组:

const animals = createAnimals([() => new Dog(), () => new Cat()]);
// type: [Dog, Cat]

TypeScript playground

Typescript相关问答推荐

使用新控制流的FormArray内部的Angular FormGroup

使用FormArray在Angular中添加排序

当类型断言函数返回假时,TypScript正在推断从不类型

APP_INITIALIZER—TypeError:appInits不是函数

参数类型undefined不能分配给参数类型字符串|未定义

防止获取发出不需要的请求

在Angular中注入多个BrowserModules,但在我的代码中只有一个

扩展函数签名中的参数类型,而不使用泛型

在TypeScrip中分配回调时,参数的分配方向与回调本身相反.为什么会这样呢?

无法正确推断嵌套泛型?

如何在TypeScrip中正确键入元素和事件目标?

类型脚本返回的类型包含无意义的泛型类型名称

获取一个TypeScrip对象,并将每个属性转换为独立对象的联合

如何从输入中删除值0

编译TypeScrip项目的一部分导致错误

如何在try 运行独立的文字脚本Angular 项目时修复Visual Studio中的MODULE_NOT_FOUND

无法缩小深度嵌套对象props 的范围

如何填写Partial的一些属性并让类型系统知道它?

组件使用forwardRef类型脚本时传递props

const 使用条件类型时,通用类型参数不会推断为 const