在推断该类型的某些部分时声明 TypeScript 类型

时间:2021-04-24 11:06:43

标签: typescript

假设您有多个模块,并且您希望每个模块都导出某个特定形状的对象。同时,对象的属性可能具有您想要在导入模块时推断的变量类型。有没有办法声明对象的类型(这样你在编写对象时就可以自动补全),同时还能推断出特定对象的属性类型?

这是一个显然不起作用的示例,因为我们明确设置了要推断的类型:

type MyObject<T> = { myProp: T }

// moduleA.ts
export const a: MyObject<any> = ({ myProp: 42 });

// moduleB.ts
export const b: MyObject<any> = ({ myProp: "A string" });

// index.ts
import { a } from "./moduleA";
import { b } from "./moduleB";

const objectMap = { a, b };

type ObjectMap = typeof objectMap

type InferredMap = {
 [P in keyof ObjectMap]: ObjectMap[P] extends { myProp: infer R } ? R : unknown
}

结果类型不出所料是 { a: any, b: any }

我们如何在编写模块时保持自动完成功能的同时制作此 { a: number, b: string }

我明白,如果我避免明确提供 ab 的类型,这些将被推断出来。但是在编写模块时我失去了自动完成功能(即我无法开始输入 m 并看到 myProp 是一个有效的属性)。

同样,我不想要求用户明确地向 MyObject 提供类型。在这个例子中,它只是一个 numberstring,但实际上这种类型可能非常复杂,我不希望用户在他们已经写出实际决定类型的值。

此外,我知道我可以用一个模块和一个函数来做到这一点,例如:

type MappedType<
  T extends { [key: string]: { myProp: any } }
> = {
  [P in keyof T]: T[P] extends { myProp: infer R } ? R : unknown
}

function getResult<T extends { [key: string]: { myProp: any } }> (map: T): MappedType<T> {
  //
}

但问题是如何跨模块边界实现相同的结果?

1 个答案:

答案 0 :(得分:2)

注意:请参阅分隔线下方的更新。

可以推断 ab 的整个类型,您根本不需要对它们进行类型声明。

// moduleA.ts
export const a = { myProp: 42 };

// moduleB.ts
export const b = { myProp: "A string" };

// index.ts
import { a } from "./moduleA";
import { b } from "./moduleB";

const objectMap = { a, b };

objectMap 的类型将是

{
    a: {
        myProp: number;
    };
    b: {
        myProp: string;
    };
}

ab 属性与 MyObject<T> 兼容,因为 TypeScript 的类型系统是结构性的,而不是名义上的。类型的名称是什么并不重要,重要的是它定义的形状。

通过上述内容,您可以获得自动完成信息(至少在 VSCode 和 TypeScript 游乐场中):

TypeScript playground showing inference on objectMap.a with myProp of type number

或者,如果您愿意,您可以通过提供属性的类型而不是 any 来将类型放在它们上:

export const a: MyObject<number> = { myProp: 42 };

在评论中,您已经澄清,不是在您希望自动完成的地方使用 objectMap,而是在定义 ab 的地方。抱歉误会了。

这与 my question here 非常相似。据我所知,你只能用一个函数来做到这一点:

function makeMyObject<T>(obj: MyObject<T>): MyObject<T> {
    return obj;
}

然后当你输入:

export const a = makeMyObject({m│
//                              ^−−−− (cursor)

...它提供 myProp: unknown 作为完成选项:

enter image description here

有时您必须求助于无所作为的功能才能获得所需的推理。 :-| (我想看到一个具有相同效果的 Java 风格的 export const a: MyObject<> = { 东西,但据我所知没有...)

相关问题