Let's say I have this array
const testData = [
{ properties: { number: 1, name: 'haha' } , second: 'this type'},
['one', 'two', 'three'],
];
I want to get the value of 'second' which is 'this type' like this:
const wantToGet = testData[0].second;
But the typescript generates an error saying
Property 'second' does not exist on type 'string[] | { properties: { number: number; name: string; }; second: string; }'.
Property 'second' does not exist on type 'string[]'
testData[0] is always an object, not an array. Why is that?
CodePudding user response:
What typescript knows is that testData
is a list of either an array of strings or an object of shape {properties: {number: number; name: string;}
. Because testData[0]
can be either of the two, you need to narrow it down to use safely.
Or you can
const testData = [
{ properties: { number: 1, name: 'haha' } , second: 'this type'},
['one', 'two', 'three'],
] as const;
CodePudding user response:
testData
is inferred as ({ ... } | string[])[]
, just like how
const thing = [1, "2", 3, "4"];
is inferred as (number | string)[]
. If you want it to be inferred as a tuple, you can use a const assertion,
const testData = [
{ properties: { number: 1, name: 'haha' } , second: 'this type'},
['one', 'two', 'three'],
] as const;
but this makes testData
immutable (even the object and array inside are immutable). If you want to be able to mutate it, you should give it an explicit type annotation:
const testData: [{ properties: { ... } ... }, string[]] = [
{ properties: { number: 1, name: 'haha' } , second: 'this type'},
['one', 'two', 'three'],
];
Or you can use a helper function to infer it as a tuple:
function tuple<T extends readonly unknown[]>(args: [...T]) { return args }
const testData = tuple([
{ properties: { number: 1, name: 'haha' } , second: 'this type'},
['one', 'two', 'three'],
]);