Search code examples
javascripttypescriptjavascript-objectsarrow-functions

Typescrit interface for an object of arrow functions


I'v faced a problem trying to define an interface for the following structure:

interface JSONRecord {
  [propName: string]: any;
}
type ReturnType = (id: string|number, field: string, record: JSONRecord) => string

export const formatDictionary = ({
  mode = "render", key = "originalValue",
  defaultKey = "originalValue"
}):ReturnType => (id, field, record) => {
  ...
}

interface Lookup {
  Dictionary: ({mode, key, defaultKey}:{mode: string, key: string, defaultKey: string}) => ReturnType,
  ...
}
export const functionLookup:Lookup = {
  Dictionary: formatDictionary,
  ...
}
export const formatField = (params:JSONRecord):string|ReturnType => {
  const type:string = params.type
  if (type === undefined) { return identity }
  const fn = functionLookup[type]
  if (fn === undefined) { return identity }
  return fn({ ...params })
}

I'm getting the following errors:

  1. In line const fn = functionLookup[type] : Element implicitly has an 'any' type becasue expression of type string can't be used to index type 'Lookup'. No index signature with parameter of type 'string' was found on type 'Lookup'.
  • I'm not really sure why is this happening, i thought that the Dictionary i defined in Lookup is supposed to be interpreted as a string. When i change Dictionary to [x: string]: ({mode, key, defaultKey}:{mode: string, key: string, defaultKey: string}) => ReturnType the error disappears, but i want to be specific with the arguments that can be passed.
  1. In line return fn({ ...params }) : Expected 3 arguments, but got 1
  • I can't really wrap my head around this, the function is clearly expecting only 1 object as an argument {mode, key, defaultKey} or is it expecting the ReturnType function there?

I would appreciate any help. Thanks a lot in advance :)


Solution

  • In you case (from sandbox):

    const anExampleVariable = "Hello World"
    console.log(anExampleVariable)
    
    // To learn more about the language, click above in "Examples" or "What's New".
    // Otherwise, get started by removing these comments and the world is your playground.
    
    interface Lookup {
        test: number
    }
    const functionLookup:Lookup = {
        test: 5
    }
    
    const params = {
        type: 'test'
    };
    const type = params.type
    const a = functionLookup[type]
    

    params variable is infered as {type: string}.

    Here functionLookup[type] you want use type as index for functionLookup, but TS does not work that way. Because you can't just use general type string as index for Lookup type.

    Lookup allows you to use only literal test as index.

    So you can add as const prefix to your params vvariable.

    const params = {
        type: 'test'
    } as const;
    

    You can make Lookup indexed:

    interface Lookup {
        test: number,
        [prop:string]:number
    }
    

    Or, you can explicitly define a Record type for params:

    
    const params:Record<string, keyof Lookup> = {
        type: 'test'
    }