node.js - Dette uttrykket kan ikke kalles. Type 'string' har ingen kallsignaturer


Jeg prøver å lage en malfil fra et objekt der nøkkelen kan være enten en streng eller en funksjon som returnerer en streng:

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
}

Mine grensesnitt er:

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 fortsetter å gi denne feilen i createDynamicTemplate selv om:

Dette uttrykket kan ikke kalles. Ikke alle komponenter av typen 'string | ((param: string) => void)' kan kalles. Typen 'string' har ingen kallbare signaturer.

Hva gjør jeg galt her?

Svar #1

Å sjekke typen til en barneegenskap til en variabel som refererer til et objekt vil ikke begrense typen til variabelobjektet. Du kan lagre verdien ved nøkkelen i en separat variabel først, og deretter sjekke den verdien for å begrense typen:

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, enda bedre, bruk Object.entries for å få nøkkelen og verdien samtidig. (Merk også at det ikke er nødvendig å angi typen til .map-parametrene - TS kan utlede det automatisk helt fint)

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

Relaterte artikler