norr
norr

Reputation: 2167

Array types checking does not work in nested object

let test: number[] = [1, 2, 3, 'a'] // correctly fails

let test2 = {
    demo: 1,
    items: <number[]> ['a', 'b'], // correctly fails
}

let test3 = {
    demo: 1,
    items: <number[]> [1, 2, 3, 'a'], // why passes if there is string inside?
}

Sandbox here

Why it passes if there is at least one correct value type, and allows rest to be wrong? How to make sure that ALL Array values in object item are certain type?

Upvotes: 3

Views: 1056

Answers (1)

CertainPerformance
CertainPerformance

Reputation: 370779

The syntax for test is somewhat different from what you're using compared to test2 and test3. This:

let test: number[] = [1, 2, 3, 'a']

annotates the type of test: it requires that test be number[]. The array being assigned to it does not fulfill that type, so it fails.

Your second and third examples are something completely different, which is type assertion. Type assertion with <> or as is basically telling TypeScript: "I know what I'm doing, this expression is of the type SomeType, even if the type-checker can't determine that from the context.

For a similar example, the following is permitted:

const something = localStorage.foobar as number;

or, equivalently

const something = <number> localStorage.foobar;

even though localStorage does not have a foobar property which is a number. (Local storage properties are either strings or functions) With as and <>s, you're asserting the type, regardless of what TS can inference, not checking the type.

The second example with test2 fails with the following error message:

Conversion of type 'string[]' to type 'number[]' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.

It's not failing because the type isn't assertable, but because the two types do not sufficiently overlap.

The test3 passes because Array<number | string> does have some overlap with Array<number>.

To fix it and have both test2 and test3 fail as desired, go back to the syntax you're using with the first example, of putting the type after a colon right after the variable name:

let test3: {
    demo: number;
    items: number[];
} = {
    demo: 1,
    items: [1, 2, 3, 'a'], // This fails - good!
}

so that TypeScript's type checker will check it properly, and result in a typing error, without doing any type-assertion.

Upvotes: 4

Related Questions