目标:根据输入类型创建函数的返回类型,使用映射类型查找返回类型。
问题:我犯了一个错误,因为受歧视的工会类型的交集冲突,我从概念上理解,但对如何构造我的类型来实现我的目标感到困惑。
Type 'Integration' is not assignable to type 'IntegrationTypeData[T]'.
Type 'IntegrationA' is not assignable to type 'IntegrationTypeData[T]'.
Type 'IntegrationA' is not assignable to type 'never'.
The intersection 'IntegrationA & IntegrationB' was reduced to 'never' because property 'name' has conflicting types in some constituents.我喜欢的类型如下:
enum Integrations {
A = 'A',
B = 'B',
}
type IntegrationMap<M extends { [key: string]: any }> = {
[Key in keyof M]: M[Key]
};
type IntegrationA = {
name: Integrations.A,
propertyA: string;
}
type IntegrationB = {
name: Integrations.B,
propertyB: number;
}
type IntegrationData = {
[Integrations.A]: IntegrationA;
[Integrations.B]: IntegrationB;
};
// this resolves to type Integration = IntegrationA | IntegrationB
type Integration = IntegrationMap<IntegrationData>[keyof IntegrationMap<IntegrationData>];
// the function I want to make have a dynamic/mapped return type
const getIntegration = <T extends Integrations>(name: T): IntegrationData[T] => {
// the type of the integrations variable is Integration[]
const integration = integrations.find((i: Integration) => i.name === name);
return integration;
};
// desired usage
// typeof intB = IntegrationB
const intB = getIntegration(Integrations.B);有人能帮助我理解如何解决这个错误,以及如何正确地输入数据,从而得到这个函数的动态类型和安全返回类型吗?
发布于 2022-09-17 00:54:40
integrations数组的元素属于联合型 (IntegrationA | IntegrationB)。
如果您查看默认调用签名的阵列法,您将看到它返回一个元素类型(本例中为IntegrationA | IntegrationB)或undefined的值。因此,您将返回一个类型为IntegrationA | IntegrationB | undefined的值。但是,由于函数的返回类型是IntegrationData[T],其中T是传入的name参数的类型。编译器不能确定前者可以分配给后者,所以它会抱怨。
您收到的关于将相交类型 IntegrationA & IntegrationB还原为类型的特定错误消息,因为确保独立于T返回Integration[T]的唯一方法是,如果您的值同时为IntegrationA和IntegrationB,这是不可能的。最好不要太沉迷于错误信息。
只需说,这里的问题是find()的返回类型对于您的目的来说太宽了。
幸运的是,有find(),它有可能返回比数组元素类型更窄的类型(但仍然可能是undefined)。如果传入的回调是一个带有表单用户定义类型保护功能的返回类型谓词的x is Y,那么将返回缩小的Y | undefined类型。
如果编译器能够理解i => i.name === name作为一个具有调用签名(i: Integration) => i is IntegrationData[T]的类型保护函数,那就太好了。不幸的是,这种情况并没有发生;TypeScript没有从实现中推断类型保护函数调用签名。在某些情况下,微软/打字稿#38390有一个开放的请求来支持这一点,但目前它并不是语言的一部分。(即使是这样,这种情况下的推断也可能超出其能力范围。)
如果您想使用i => i.name === name作为类型保护函数,则需要这样的注释它:
const getIntegration = <T extends Integrations>(name: T): IntegrationData[T] => {
const integration = integrations.find(
(i: Integration): i is IntegrationData[T] => i.name === name
// annotated ---> ^^^^^^^^^^^^^^^^^^^^^^^^^
);
return integration!;
};注释可以让您在大多数情况下都能到达那里。不过,它仍然不能消除undefined。所有编译器都知道,integrations实际上没有IntegrationData[T]类型的元素。所以integration可能是undefined。您可以通过在if (!integration) throw new Error("OH NO I WAS WRONG")之前编写return来显式地处理这一问题。或者,如果您确定它实际上不是undefined,您可以使用非空断言运算符(!)告诉编译器。在编写return integration!时,您声称integration将不是undefined或null,因此可以将类型IntegrationData[T] | undefined的值视为IntegrationData[T]。
现在它编译时没有错误。
https://stackoverflow.com/questions/73739372
复制相似问题