node.js - Detta uttryck är inte anropbart. Typen 'string' har inga anropssignaturer


Jag försöker skapa en mallfil från ett objekt där nyckeln kan vara antingen en sträng eller en funktion som returnerar en sträng:

export const createDynamicTemplate = (
  templateParams: CreateDynamicTemplateParams
) => {
  const { template, projectPath = '', param = '' } = templateParams
  const updatedTemplateArr = Object.keys(template).map((key: string) => {
      return {
        [key]: {
          filePath: `${projectPath}/${key}`,
          template: typeof template[key] === 'function' ? 
          template[key](param) : template[key],
        },
      }
  })
  const updatedTemplate = Object.assign({}, ...updatedTemplateArr)
  return updatedTemplate
}

Mina gränssnitt är:

export interface TemplateObject {
  [key: string]: string
}

export interface FunctionalTemplateObject {
  [key: string]: (param: string) => void
}

export interface CreateDynamicTemplateParams {
  template: FunctionalTemplateObject | TemplateObject
  projectPath: string
  param: string
}

Det fortsätter att ge detta fel i createDynamicTemplate dock:

Detta uttryck kan inte anropas. Inte alla beståndsdelar av typen 'string | ((param: string) => void)' kan anropas. Typen 'string' har inga anropssignaturer.

Vad gör jag för fel här?

Svar #1

Att kontrollera typen av en barn-egenskap hos en variabel som refererar till ett objekt kommer inte att begränsa typen av variabelobjektet. Du kan först spara värdet på nyckeln i en separat variabel och sedan kontrollera det värdet för att begränsa dess typ:

const updatedTemplateArr = Object.keys(template).map((key: string) => {
  const item = template[key];
  if (typeof item === 'function') {
    return {
      [key]: {
        filePath: `${projectPath}/${key}`,
        template: item(param),
      },
    }
  }
})

Eller ännu bättre, använd Object.entries för att få nyckeln och värdet på en gång. (Observera också att det inte behövs att ange typen för .map-parametrarna - TS kan härleda det automatiskt utan problem)

const updatedTemplateArr = Object.entries(template).map(([key, value]) => {
  if (typeof value === 'function') {
    return {
      [key]: {
        filePath: `${projectPath}/${key}`,
        template: value(param),
      },
    }
  }
})

Relaterade artiklar