首页 > 解决方案 > switch 语句中的打字稿类型生成问题

问题描述

我有这个渲染对象类型的映射函数。

function mapStuffs(fields: any) {
    switch (fields.type) {
        case "NewStuffs":
            return {
                type: "NewStuffs" as const,
                stuff: fields.stuff
            };
        case "StuffFile":
            const fileName = "jadflkjs";
            const stuffId = "adlkajsf";
            return {
                type: "StuffFile" as const,
                fileName,
                stuffId
            };
        default:
            return {
                type: "ExistingStuff" as const
            };
    }
}

当我构建时,生成的类型是:

mainstuff:
        | {
              stuff: string | undefined;
              type: "NewStuffs";
              fileName?: undefined;
              stuffId?: undefined;
          }
        | {
              type: "StuffFile";
              fileName: string;
              stuffId: string;
          }
        | {
              type: "ExistingStuff";
              fileName?: undefined;
              stuffId?: undefined;
          };

我不明白如何在不需要时将fileNamestuffId作为可选参数删除。它是打字稿错误吗?我想要的是这种类型:

mainstuff:
        | {
              stuff: string | undefined;
              type: "NewStuffs";
          }
        | {
              type: "StuffFile";
              fileName: string;
              stuffId: string;
          }
        | {
              type: "ExistingStuff";
          };

标签: typescripttypes

解决方案


这不是 TypeScript 错误。这是预期的行为,因为 TypeScript 2.7为对象文字引入了改进的类型推断fileName某些返回值没有包含and的事实stuffId使编译器认为缺少应该反映在返回类型中。

TypeScript 中的类型推断算法是一组启发式算法,语言设计者试图猜测在某些情况下大多数人希望看到什么样的东西。如果你不喜欢推断的类型,你可以自由地用你喜欢的任何类型来注释你的mapStuffs()函数的返回类型,并且编译器会对此感到满意,假设你的函数实现符合它:

type MappedStuff = {
    stuff: string | undefined;
    type: "NewStuffs";
} | {
    type: "StuffFile";
    fileName: string;
    stuffId: string;
} | {
    type: "ExistingStuff";
};

function mapStuffs(fields: any): MappedStuff {

    switch (fields.type) {
        case "NewStuffs":
            return {
                type: "NewStuffs" as const,
                stuff: fields.stuff
            };
        case "StuffFile":
            const fileName = "jadflkjs";
            const stuffId = "adlkajsf";
            return {
                type: "StuffFile" as const,
                fileName,
                stuffId
            };
        default:
            return {
                type: "ExistingStuff" as const
            };
    }
}

Playground 代码链接


推荐阅读