Fabio Spampinato Fabio Spampinato - 2 months ago 6
TypeScript Question

How can I define the general structure of an object without adding every single one of its properties to the definition?

Let's say I have an object like the following, mapping errors names to their code and message:

let Errors = {
FOO: [1, 'Foo error'],
BAR: [2, 'Bar error'],
BAZ: [3, 'Baz error']
}


Every property has the inferred type of
(number | string)[]
, good, but we know that the type is actually the more specific
[number, string]
. In order to let TypeScript know about it, as far as I understand, we have to do something like the following:

let Errors = {
FOO: [1, 'Foo error'] as [number, string],
BAR: [2, 'Bar error'] as [number, string],
BAZ: [3, 'Baz error'] as [number, string]
}


Is it possible to add the proper types to all the properties in a cleaner way that avoids all these repetitions?

Answer

There's no way to tell the compiler that all of the properties have the same type.

You can use a type alias to make it a bit better:

type ErrorInfo = [number, string];

let Errors = {
    FOO: [1, 'Foo error'] as ErrorInfo,
    BAR: [2, 'Bar error'] as ErrorInfo,
    BAZ: [3, 'Baz error'] as ErrorInfo
};

Another option is to have a type for your Errors:

type ErrorInfo = [number, string];

interface ErrorMap = {
    FOO: ErrorInfo;
    BAR: ErrorInfo;
    BAZ: ErrorInfo;
}

let Errors: ErrorMap = {
    FOO: [1, 'Foo error'],
    BAR: [2, 'Bar error'],
    BAZ: [3, 'Baz error']
};

There's defiantly a repetition here, but it makes a good separation between the interface and the actual runtime value.