问题
I'm typing up a localization-library, and I'm aiming to have it strongly typed (as it will be re-used in multiple angular-applications) and - at the same time - backwards compatible so that we won't have to re-write all existing localization-files.
However, the structure of said localization-files is causing me a bit of a headache. Per example:
{
'any-random-key': 'This is a string',
'another-random-key': {
'random-key': 'This is a string'
},
'yet-another-random-key': {
'random-key-2': 'This is a string',
'random-key-3': {
'random-key-4': 'This is a string',
'random-key-5': {
'random-key-6': 'This is a string'
}
}
},
'and-yet-another-random-key': {
'random-key-6': {
'random-key-7': {
'random-key-8': 'This is a string'
},
'random-key-9': 'This is a string'
}
}
}
Now - I suppose I could say that the service accepts translations: any
or translations: object
- but that's a little too random (no pun intended) for my liking.
So I tried using two different interfaces:
export interface ITranslation {
[s: string]: string;
}
export interface ITranslations {
[s: string]: ITranslation;
}
However that fails on any-random-key
saying: Type 'string' is not assignable to type 'ITranslation'
So I tweak my ITranslations
-interface so that it becomes
export interface ITranslations {
[s: string]: ITranslation | string;
}
Which fixes the above error, but introduces a new one on 'and-yet-another-random-key'
saying Property ''and-yet-another-random-key'' is incompatible with index signature.
At this point I am a little stumped. Is what I am trying to achieve (strong typing of the legacy structure) simply not plausible?
回答1:
For any arbitrary level of nesting (in other words, your data object can be as many levels deep as you want), you can simply self-reference the interface as such:
/** @interface */
export interface ITranslations {
[s: string]: ITranslations | string;
}
See the above example on TypeScript playground.
If you want to only allow 3-level deep nesting, then the interface will have to be verbose: TypeScript does not allow you to define how "deep" (i.e. the degree of nesting):
/** @interface */
export interface ITranslations<T = string> {
[s: string]: T | string;
}
/** @type */
export type ITranslationsMax3Levels = ITranslations<ITranslations<ITranslations<ITranslations>>>;
const data: ITranslationsMax3Levels = { ... }
See the above example on TypeScript playground.
回答2:
Seems the solution was easier than I dared hope for:
export interface ITranslations {
[s: string]: ITranslations | ITranslation | string;
}
来源:https://stackoverflow.com/questions/57267444/how-can-i-define-an-interface-for-a-object-array-containing-key-value-pairs-as-w