1

I have the following code:

type StringMapType<K extends string[]> = Record<K[number], string>

const en = {
  'general': {
    'hi': {
      string: 'Aenean ullamcorper neque id elementum commodo. {{firstName}}',
      params: ['firstName']
    },
     'bye': {
      string: 'Aenean ullamcorper neque id elementum commodo.',
      params: null
    }
  },
} as const


const getLocalizedString = <ContextType extends keyof typeof en, KeyType extends keyof typeof en[ContextType], ParamsType extends typeof en[ContextType][KeyType]['params']>(context: ContextType, key: KeyType, ...params: typeof en[ContextType][KeyType]['params'] extends null ? [undefined?] : [StringMapType<ParamsType>]) => {
  // Code that would return the correct value
}


getLocalizedString('general', 'hi', {
  firstName: 'John'
})

For some reason, I'm getting an error on the ParamsType saying that Type '"params"' cannot be used to index type. The code itself works and does what I want, just wondering if there is any way how to get around this error.

Demo

Thanks in advance

Solution

Based on @seti's answer

const en = {
  general: {
    hi: {
      string: 'hi, {{firstName}}',
      params: ['firstName'] as const,
    },
    bye: {
      string: 'bye',
      params: [] as const,
    }
  },
} as const

const translations = {
  en,
} as const

const language = 'en'

type CT = keyof typeof en
type KT = keyof typeof en[CT]
type ParamsType<KeyType extends KT> = typeof en[CT][KeyType]['params'][number]
type StringType<KeyType extends KT> = typeof en[CT][KeyType]['string']

const getLocalizedString = <ContextType extends CT = CT, KeyType extends KT = KT>(
  context: ContextType,
  key: KeyType,
  ...params: ParamsType<KeyType> extends undefined ? [undefined?] : [{ [key in ParamsType<KeyType>]: string }]
): StringType<KeyType> => {

  return translations[language][context][key].string
}

getLocalizedString('general', 'hi', {firstName: 'John'})

getLocalizedString('general', 'bye')
2
  • Why do you need to capture the valid keys at the type level? Commented May 19, 2022 at 11:50
  • I think this is a limitation of TypeScript. Commented May 19, 2022 at 13:59

1 Answer 1

1

I have wrote Example Solution for you, and have split the declarations into several parts

So this monstrocity:

type StringMapType<K extends string[]> = Record<keyof K[number] & string, string>

const en = {
  'general': {
    'hi': {
      string: 'Aenean ullamcorper neque id elementum commodo. {{firstName}}',
      params: ['firstName', 'test'] as const
    },
     'bye': {
      string: 'Aenean ullamcorper neque id elementum commodo.',
      params: ['x'] as const
    }
  },
} as const;


type X = keyof typeof en;
type Y = keyof typeof en[X];
type W = typeof en[X][Y]['string'];
type F<YY extends Y> = typeof en[X][YY]['params'][number];
type G<YY extends K<Y>> = {[key in F<YY>]: string};
type K<YY extends Y> = YY;


const getLocalizedString = <KK extends Y = Y, GG = Required<{[key in F<KK>]: string}>, XX extends X = X>(context: XX, key: KK, ...params: GG[]) => {

}



getLocalizedString('general', 'hi', {
  firstName: 'John',
  aaa: 'a',
});

getLocalizedString('general', 'bye', {
 'y': '',
});

From that you can experiment more. Only one issue with this - it do not check against wrong, but you have some starting point now

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks a ton! This was pretty much all I needed, did a couple of modifications to check for errors and got it working great!
Can you share yours code so we all could see it in the end?^^
edited the question with a solution :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.