镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

Type parameter explicitly constrained by unknown should not be assignable to {} #26796

Description

TypeScript Version: master (2deb318)

Search Terms: conditional type variable parameter undefined null empty object constraint

Code

// With --strictNullChecks
type Test1 = [unknown] extends [{}] ? true : false;  // false
type IsDefinitelyDefined<T extends unknown> = [T] extends [{}] ? true : false;
type Test2 = IsDefinitelyDefined<unknown>;  // true, should be false

function oops<T extends unknown>(arg: T): {} {
    return arg;  // no error, should be an error (unknown not assignable to {})
}
console.log(oops(null).constructor);  // bang!

Expected behavior / Actual behavior: as marked

Playground Link: link (remember to enable strictNullChecks)

Related Issues: didn't find any

Discovered via https://stackoverflow.com/questions/52105268 .

Activity

  1. ahejlsberg commented on Aug 31, 2018

    @ahejlsberg
    Member

    In the early days before --strictNullChecks, the {} type was our top type. With --strictNullChecks we carved out null and undefined and effectively our top type then became {} | null | undefined. However, for reasons of backward compatibility we kept {} as the default inference for an unconstrained type parameter and we kept the rule that allows an unconstrained type parameter to be assigned to {}.

    We now have a proper top type called unknown and if it wasn't for backward compatibility we'd switch from {} to unknown in the situations above. However, it would be a significant breaking change.

  2. mattmccutchen commented on Aug 31, 2018

    @mattmccutchen
    ContributorAuthor

    I would happily take the breaking change (under a new strict flag) for the soundness; in fact, I assumed it had come as part of --strictNullChecks until I discovered this issue. (What was the specific reason that the change was unacceptable to make as part of --strictNullChecks, which was a large breaking change already?)

    If you don't want to do that, we could at least make a type parameter explicitly constrained by unknown not assignable to {}; nobody should be relying on that behavior. If we do that and then people use a lint rule to require every type parameter in their code to have a constraint (either unknown, {}, or something else), then we'll be in pretty good shape; the standard library may still have legacy unconstrained type parameters, but it seems unlikely to me that any of them will expose the buggy behavior. Shall I write the PR for the assignability change?

  3. changed the title [-]Conditional type assumes type variable is assignable to `{}` but it might be null/undefined[/-] [+]Type parameter explicitly constrained by `unknown` should not be assignable to `{}`[/+] on Aug 31, 2018
  4. RyanCavanaugh commented on Sep 17, 2018

    @RyanCavanaugh
    Member

    Per notes in #26954, committed to trying it, at least

  5. ahejlsberg commented on Dec 10, 2018

    @ahejlsberg
    Member

    The original issue here is actually not controversial. A type parameter with an explicit constraint of unknown shouldn't be assignable to {}. We should just fix that.

    The larger issue is whether it is possible for us to switch the default constraint for type parameters to unknown as we discussed in #26954. We should run that experiment and discuss.

  6. NN--- commented on Jan 11, 2019

    @NN---

    So, is it planned for next release ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

CommittedThe team has roadmapped this issueSuggestionAn idea for TypeScript

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions