user3826456
user3826456

Reputation: 21

TypeScript Named Tuple - Target requires 1 element(s) but source may have fewer.(2345)

I'm trying to utilize a named tuple (in this instance AnniversaryPropertyConfig) to describe a function argument in the following simplified code.

interface AnniversaryParameters {
    value?: 'date-and-or-time' | 'text';
    altid?: number | string;
    calscale?: 'gregorian';
}

type AnniversaryPropertyConfig = [value: string, parameters?: AnniversaryParameters];

function main(config: AnniversaryPropertyConfig) {
    return config;
}

const config = ['19960415', { value: 'text' as const }];

main(config);

However I keep receiving the following error: "Target requires 1 element(s) but source may have fewer.(2345)" I've tried to apply as const assertions to the config array and its values but to no avail. The error does go away if I typecast the config variable to the AnniversaryPropertyConfig type. But I feel like this is something that TypeScript should be able to infer without assistance.

For reference a link to an applicable TypeScript Playground can be found here.

Upvotes: 2

Views: 5371

Answers (2)

Matthieu Riegler
Matthieu Riegler

Reputation: 55604

Your problem is that you defined AnniversaryPropertyConfig as a tuple : [value: string, parameters?: AnniversaryParameters]

Arrays are never infered as tuple, so you have to explicitly assert the type.

interface AnniversaryParameters {
    value?: 'date-and-or-time' | 'text';
    altid?: number | string;
    calscale?: 'gregorian';
}

type AnniversaryPropertyConfig = [value: string, parameters?: AnniversaryParameters];

function main(config: AnniversaryPropertyConfig) {
    return config;
}

const config: AnniversaryPropertyConfig = ['19960415', { value: 'text' }];

main(config);

And do yourself a favor, avoid by all means type assertions like myVar as MyType. It's never a good idea.

Upvotes: 1

kshetline
kshetline

Reputation: 13700

The only way I found to get rid of the error was to do this:

const config = ['19960415', { value: 'text' }] as AnniversaryPropertyConfig;

...or...

const config: AnniversaryPropertyConfig = ['19960415', { value: 'text' }];

From what I can guess, TypeScript's type inference sees ['19960415', { value: 'text' }] as an array that could have strings in any position in the array, or objects that match { value: 'text' } at any position in the array. So the inferred type doesn't have any enforced order for the array elements, making it too broad a type to automatically agree with AnniversaryPropertyConfig.

Upvotes: 0

Related Questions