Skip to content

undefined satisfies TestType = 'blah' | number in certain situations, but not others #33787

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
yay opened this issue Oct 3, 2019 · 4 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@yay
Copy link

yay commented Oct 3, 2019

TypeScript Version: 3.4.0-dev.201xxxxx

Search Terms:

npx tsc --version: Version 3.7.0-dev.20191003

Code
Run with npx tsc index.ts --out index.js --noImplicitAny --strictNullChecks

type TestType = 'blah' | number;
const testObjects = [
    {test: undefined, str: 'foo'},
    {test: 42, str: 'bar'}
] as {test: TestType, str: string}[]; // Why is this not an error?
const obj1: TestType = undefined; // Type 'undefined' is not assignable to type 'TestType'.
const obj2 = undefined as TestType; // Conversion of type 'undefined' to type 'TestType' may be a mistake because neither type sufficiently overlaps with the other.

Expected behavior:
This should be an error

const testObjects = [
    {test: undefined, str: 'foo'},
    {test: 42, str: 'bar'}
] as {test: TestType, str: string}[];

Something in the lines of Conversion of type 'type1' to type 'type2' may be a mistake because neither type sufficiently overlaps with the other.

Actual behavior:
This compiles without errors:

const testObjects = [
    {test: undefined, str: 'foo'},
    {test: 42, str: 'bar'}
] as {test: TestType, str: string}[];

Playground Link:

https://www.typescriptlang.org/play/?ts=3.7-Beta#code/C4TwDgpgBAKhDOwbmgXigcgEYBsCGAFhlAD5QB2ArgLZYQBOA3AFADGA9uYlMAsAPJYAVhFbB4UdAG1mUOVADevRAC4olcgBMIAMwCW5CJoA0URPTUYd7dhgC+x2fKV81AFgBMp85ax569swAulB4Ei6qsHzIkN7AFmbxBgDmdlJBjFAA9FlQAOoEIFB6EsAEJRTswKHkUAz07PQA-Gyc3OzCAIxqcIgxaOpaugZGmTmwKJga2vqGmsQV5FWh8PB6yeR4uNDA7DyTGL1IKBgAdK1c1R1CHpKDMyOaK1F9KGO5AMKcAG4Ma5xQdg6faQKZDWZGYi7EHQQ7RE5Qah4Ip0UKIkrAPAAa2gdFYeEo8Gghj0ZQYMLMlB0+lYegg5GAOCK7F+9HwYAkAHdSQQeARoFV+fRzkA

Related Issues:

@MartinJohns
Copy link
Contributor

When you use a type-assertion with the as operator, then you are responsible to make sure the type matches. With a type-assertion you basically say "hey compiler, trust me on this".

To fix it just type your variable explicitly instead of using a type-assertion.

#33657 is related to this.

@DanielRosenwasser DanielRosenwasser added Working as Intended The behavior described is the intended behavior; this is not a bug and removed Working as Intended The behavior described is the intended behavior; this is not a bug labels Oct 3, 2019
@DanielRosenwasser
Copy link
Member

Type assertions check in two directions and each time use a notion called "comparability". When checking comparability, instead of checking if every constituent of a union is related to a type, it checks if any constituent is related. Here's what you're running into:

  • A type assertion! Is either type comparable to the other?
    • Is Array<{test: undefined, str: 'foo'} | {test: 42, str: 'bar'}> comparable with Array<{ test: 'blah' | number, str: string }>?
      • Is {test: undefined, str: 'foo'} | {test: 42, str: 'bar'} comparable with { test: 'blah' | number, str: string }?
        • Is {test: 42, str: 'bar'} comparable with { test: 'blah' | number, str: string }?
          • Is {test: 42, str: 'bar'}["test"] comparable with { test: 'blah' | number, str: string }["test"]?
            • Is 42 comparable with number?
              • Yes!

@DanielRosenwasser DanielRosenwasser added the Working as Intended The behavior described is the intended behavior; this is not a bug label Oct 3, 2019
@yay
Copy link
Author

yay commented Oct 4, 2019

So basically, if there's a single number there, it's all good:

{
    const x = [{
        z: undefined
    }];
    const y = x as { z: number }[]; // NOT ok
}

{
    const x = [{
        z: undefined
    }, {
        z: 42
    }];
    const y = x as { z: number }[]; // ok
}

{
    const x = [{
        z: undefined
    }, {
        z: "42"
    }];
    const y = x as { z: number }[]; // NOT ok
}

{
    const x = [{
        z: undefined
    }, {
        z: {}
    }];
    const y = x as { z: number }[]; // ok, but weird
}

{
    const x = [{
        z: null
    }, {
        z: 42
    }, {
        z: {}
    }, {
        z: "foobar"
    }];
    const y = x as { z: number }[]; // ok
}

It makes sense, although I wouldn't call it intuitive.
Thank you for the explanation.

@typescript-bot
Copy link
Collaborator

This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

4 participants