You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript如何定义第二个参数类型依赖首个参数值的函数类型

问题根因

TypeScript 不会自动为两个独立声明的联合类型参数建立关联约束:即使在 switch 分支中收窄了fileType的字面量类型,TS 仍会判定fileData为TFileType1 | TFileType2的联合类型,无法自动匹配到当前分支对应的具体类型,因此调用转换函数时抛出类型不匹配错误。

解决方案

通过映射类型+泛型约束建立两个参数的类型关联,即可让TS在分支判断时自动收窄类型,同时保证后续赋值逻辑的类型安全,后续扩展文件类型时也只需要修改映射配置,维护成本更低。

第一步:定义类型映射关系

先建立文件类型与原始内容、转换结果的对应关系,替代零散的联合类型声明:

// 文件类型 -> 原始内容结构 映射
type FileTypeMap = {
  type1: TFileType1
  type2: TFileType2
}

// 文件类型 -> 转换后结构 映射
type TransformResultMap = {
  type1: TFile1Transform
  type2: TFile2Transform
}

原有基础类型可以直接从映射派生,不需要重复声明:

type TFileTypes = keyof FileTypeMap // 等价于 'type1' | 'type2'
type TFileContentType = FileTypeMap[TFileTypes] // 等价于 TFileType1 | TFileType2

第二步:改造parseFileData为泛型函数

通过泛型约束入参fileType和fileData的类型必须一一对应,同时明确返回值和入参类型的关联:

const parseFileData = <T extends TFileTypes>(
  fileType: T, 
  fileData: FileTypeMap[T]
): TransformResultMap[T] => {
  switch(fileType) {
    case 'type1': {
      // 此分支下TS会自动收窄fileData为TFileType1,无类型错误
      return transformFile1Data(fileData) as TransformResultMap[T]
    }
    case 'type2': {
      // 此分支下TS会自动收窄fileData为TFileType2,无类型错误
      return transformFile2Data(fileData) as TransformResultMap[T]
    }
    default:
      throw new Error(`不支持的文件类型: ${fileType}`)
  }
}

此处的as类型断言是安全的:分支判断已经保证了返回值和泛型T的类型完全匹配。

第三步:修正fileData数组类型

给fileData添加可辨识联合类型标注,保证遍历时fileType和content的类型关联,让loadFileData中的赋值逻辑也能通过类型校验:

// 定义文件数据项的可辨识联合类型
type FileDataItem = {
  [K in TFileTypes]: {
    fileType: K
    content: FileTypeMap[K]
  }
}[TFileTypes]

// 给数组添加类型标注
const fileData: FileDataItem[] = [
  {
    fileType: 'type1',
    content: {
      name: 'fname',
      val1: 'val1'
    }
  },
  {
    fileType: 'type2',
    content: {
      name: 'fname2',
      val2: 'val2'
    }
  }
]
完整可运行代码
type TFileType1 = {
    name: string
    val1: string
}

type TFileType2 = {
    name: string
    val2: string
}

type TFile1Transform = {
    val1t: string,
    val2t: string
}

type TFile2Transform = {
    val11t: string
    val22t: string
}

type TProjectData = {
    'type1'?: TFile1Transform,
    'type2'?: TFile2Transform
}

// 类型映射定义
type FileTypeMap = {
  type1: TFileType1
  type2: TFileType2
}
type TransformResultMap = {
  type1: TFile1Transform
  type2: TFile2Transform
}
type TFileTypes = keyof FileTypeMap
type TFileContentType = FileTypeMap[TFileTypes]
type FileDataItem = {
  [K in TFileTypes]: {
    fileType: K
    content: FileTypeMap[K]
  }
}[TFileTypes]

const fileData: FileDataItem[] = [
    {
        fileType: 'type1',
        content: {
            name: 'fname',
            val1: 'val1'
        }

    },
    {
        fileType: 'type2',
        content: {
            name: 'fname2',
            val2: 'val2'
        }

    }
]

const loadFileData = () => {
    const projectData: TProjectData = {}

    for (const data of fileData) {
        const fileType = data.fileType
        const resultData = parseFileData(fileType, data.content)
        projectData[fileType] = resultData
    }

    return projectData

}

const transformFile1Data = (fileData: TFileType1): TFile1Transform => {
    return {
        val1t: fileData.name,
        val2t: fileData.val1
    }
}

const transformFile2Data = (fileData: TFileType2): TFile2Transform => {
    return {
        val11t: fileData.name,
        val22t: fileData.val2
    }
}

const parseFileData = <T extends TFileTypes>(
  fileType: T, 
  fileData: FileTypeMap[T]
): TransformResultMap[T] => {
    switch(fileType) {
        case 'type1': {
            return transformFile1Data(fileData) as TransformResultMap[T]
        }
        case 'type2': {
            return transformFile2Data(fileData) as TransformResultMap[T]
        }
        default:
          throw new Error(`不支持的文件类型: ${fileType}`)
    }
}

内容的提问来源于stack exchange,提问作者Adharsh M

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 08:31:09