Skip to content
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

Certain conditional types allow unsound assignments #55733

Open
mkantor opened this issue Sep 13, 2023 · 5 comments
Open

Certain conditional types allow unsound assignments #55733

mkantor opened this issue Sep 13, 2023 · 5 comments
Labels
Bug A bug in TypeScript Cursed? It's likely this is extremely difficult to fix without making something else much, much worse Help Wanted You can do this
Milestone

Comments

@mkantor
Copy link
Contributor

mkantor commented Sep 13, 2023

πŸ”Ž Search Terms

"conditional type" generic assignment

πŸ•— Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about conditional types

⏯ Playground Link

https://www.typescriptlang.org/play?#code/C4TwDgpgBAQg9gDwDwBUB8UC8UDeUBuAhgDYCuEAXFClAL4BQ9okUAqgHYBGiAku+xABOqDNhoQEwCOwAmAZ1iIkAS3YAzIVABKGAPxsuvfkKQ6oVPKUMIIMqjQbNoHbsnRYDrvgOHoA2gDkVq62AQC6jDIQAMbEhILQalbRwMpw7FDBSugAFAj2AJRULtlojEnsKWkZEoQAtmDEECJ5hbj0UFBNwFCEHlkIeQUdvR4BwAAWygpyE3CkxDJQnNCENYKCcIIB9LRAA

πŸ’» Code

type Box<T> = { value: T }

type UnboxInner<T> = T extends Box<infer R> ? UnboxInner<R> : { unboxed: T }
type Unbox<T> = UnboxInner<T>['unboxed']

declare function unbox<T>(x: T): Unbox<T>

function example<T>(x: T) {
  let a = unbox(x)
  a = 'this should be an error'
}

πŸ™ Actual behavior

In example we can assign arbitrary values to a, even though it's typed as Unbox<T>.

πŸ™‚ Expected behavior

Attempting to assign invalid values to a (just about anything, since its type depends on a type parameter) should cause a type error.

Additional information about the issue

These issues may possibly be related:

cc @webstrand

@RyanCavanaugh RyanCavanaugh added Bug A bug in TypeScript Help Wanted You can do this Cursed? It's likely this is extremely difficult to fix without making something else much, much worse labels Sep 13, 2023
@RyanCavanaugh RyanCavanaugh added this to the Backlog milestone Sep 13, 2023
@Andarist
Copy link
Contributor

This is a fun one.

The constraint of the object type of this type:

type Unbox<T> = UnboxInner<T>['unboxed']

is computed as

type BaseConstraintOfObjectType = { unboxed: unknown; } | { unboxed: T; }

This makes sense because the constraint is computed based on both branches of this conditional type and the infer R is also "replaced" with its own constraint (and that is unknown).

So... later we unpack the 'unboxed' property from this union, so we end up with unknown | T and that is reduced to just unknown (it's not that the reduction thing matters here though). And string can be related to unknown.

@GheorgheP
Copy link

But why is allowed the assignment to a variable of type unknown?
Isn't this the real issue?

@Andarist
Copy link
Contributor

You can always assign things to their supertypes and unknown is like an ultimate supertype. Everything is assignable to unknown (except never). If you think about types in terms of sets then unknown is like a set that contains everything.

@GheorgheP
Copy link

Hmmm, how then the any type is described and at what point any is different to unknown?
Sure I don't know how to describe the unknown in terms of sets, but this form looks more like any.
Shouldn't unknown be something like bottom type?

@fatcerberus
Copy link

any means "this value won't be typechecked". unknown means "any possible value" but doesn't disable typechecking (it's not assignable to anything except itself).

Shouldn't unknown be something like bottom type?

No, the bottom type is never.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Cursed? It's likely this is extremely difficult to fix without making something else much, much worse Help Wanted You can do this
Projects
None yet
Development

No branches or pull requests

5 participants