首页 > 解决方案 > 如何正确索引和修改通用部分

问题描述

这是我的第一个泛型类型函数,如果有人能帮助我理解 Partials 和一般 TS 行为,我将不胜感激。

目的是什么:
1. 传递类型的对象<T>
2. 修改它并返回类型的预期对象<U>

下面的示例带有代码沙箱中的实时警告: https ://codesandbox.io/s/small-wood-yq14e

PS:我对如何在 TS 最佳实践中实际处理整个事情的新想法持开放态度:-)

export type ObjectWithStrings = { [index: string]: string }


// some demo data
const CONTAINER_NUTRIENTS_NAMES_ORDER: ObjectWithStrings = {}
const LIPIDS_NUTRIENTS_NAMES_ORDER: ObjectWithStrings = {}
const NUTRIENTS_MODEL_MAP: ObjectWithStrings = {}

function _sortNutrientsModel<T> (nutrientsModel: T) {
  const sortedNutrientsModel: Partial<T> = {}

  for (const sectionName in CONTAINER_NUTRIENTS_NAMES_ORDER) {
    if (CONTAINER_NUTRIENTS_NAMES_ORDER.hasOwnProperty(sectionName)) {
      /* 
      sortedNutrientsModel[sectionName]:
      Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Partial<T>'.
      No index signature with a parameter of type 'string' was found on type 'Partial<T>'.ts(7053)

      nutrientsModel[sectionName]:
      Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'unknown'.
      No index signature with a parameter of type 'string' was found on type 'unknown'.ts(7053) */
      sortedNutrientsModel[sectionName] = nutrientsModel[sectionName]
    }
  }

  for (const sectionName in LIPIDS_NUTRIENTS_NAMES_ORDER) {
    /* 
    Property 'lipids' does not exist on type 'T'.ts(2339) */
    if (LIPIDS_NUTRIENTS_NAMES_ORDER.hasOwnProperty(sectionName) && sortedNutrientsModel.lipids.sections[sectionName]) {
      sortedNutrientsModel.lipids.sections[sectionName] = nutrientsModel.lipids.sections[sectionName]
    }
  }

  return sortedNutrientsModel
}

export function createNutrientsModel<T extends object, U> (nutrients: T) {
  const nutrientsModel: Partial<U> = {}

  for (const nutrientName in nutrients) {
    if (nutrients.hasOwnProperty(nutrientName)) {
      const nutrientLocation = NUTRIENTS_MODEL_MAP[nutrientName]

      if (typeof nutrientLocation === `string`) {
        const nutrientValues = nutrients[nutrientName]

        switch (nutrientLocation.length) {
          case 0: /* Container nutrient section */
            /*
            Type 'Extract<keyof T, string>' cannot be used to index type 'Partial<U>'.ts(2536) */
            if (typeof nutrientsModel[nutrientName] === `undefined`) {
             /*
              Type 'Extract<keyof T, string>' cannot be used to index type 'Partial<U>'.ts(2536) */
              nutrientsModel[nutrientName] = {}
            }

           /*
            Type 'Extract<keyof T, string>' cannot be used to index type 'Partial<U>'.ts(2536) */
            nutrientsModel[nutrientName].values = nutrientValues
            break
          default: /* Nutrient section */
           /*
            Type 'Extract<keyof T, string>' cannot be used to index type 'Partial<U>'.ts(2536) */
            if (nutrientsModel[nutrientLocation] === `undefined`) {
             /*
              Type 'Extract<keyof T, string>' cannot be used to index type 'Partial<U>'.ts(2536) */
              nutrientsModel[nutrientLocation] = {}
            }

           /*
            Type 'Extract<keyof T, string>' cannot be used to index type 'Partial<U>'.ts(2536) */   
            if (typeof nutrientsModel[nutrientLocation].sections === `undefined`) {
              nutrientsModel[nutrientLocation].sections = {}
            }

           /*
            Type 'Extract<keyof T, string>' cannot be used to index type 'Partial<U>'.ts(2536) */ 
            nutrientsModel[nutrientLocation].sections[nutrientName] = {
              values: nutrientValues
            }
        }
      }
    }
  }

  return _sortNutrientsModel(nutrientsModel) as U
}

更新NutrientsType示例

interface BalanceModelSection {
  DRI: {
    AI: number,
    AMDR: BalanceModelAMDR
    EAR: number,
    RDA: number,
    UL: number,
    unit: string
    [index: string]: string | number | BalanceModelAMDR
  }
}

interface BalanceRecordSectionValues {
  converted: {
    quantity: number
    recommended: number
    unit: string
  }
  quantity: number
  percentage: string
}

interface BalanceRecordSection extends
  BalanceRecordSectionValues,
  BalanceModelSection {}

interface BalanceRecordNutrients {
  [index: string]: BalanceRecordSection | BalanceRecordProgressSection
  energy: BalanceRecordSection
}

标签: typescript

解决方案


推荐阅读