Skip to content

"is assignable to the constraint of type but could be instantiated with a different subtype of constraint" error with assetion function #39036

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
mateja176 opened this issue Jun 12, 2020 · 1 comment
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed

Comments

@mateja176
Copy link

mateja176 commented Jun 12, 2020

TypeScript Version: 3.9.4

Search Terms:

is assignable to the constraint of type

Code

const isNil = <A extends any>(a: A) => a === undefined || a === null;

type DeepRequired<O extends {}> = {
  [key in keyof O]: O[key] extends {}
    ? DeepRequired<O[key]>
    : NonNullable<O[key]>;
};

export function assertNonNullable<O extends {}>(
  object: O,
): asserts object is DeepRequired<O> { // throws
  Object.entries(object).forEach(([key, value]) => {
    if (typeof value === 'object' && value !== null) {
      assertNonNullable(value);
    }
    if (isNil(value)) {
      throw new Error(`Key ${key} is required, but the provided value is nil`);
    }
  });
}

interface MaybeA {
  a?: number;
}

const a: MaybeA = { a: undefined };

assertNonNullable(a);

const b = a.a;

Expected behavior:

No error is thrown

Actual behavior:

The following error is thrown:

A type predicate's type must be assignable to its parameter's type.
  Type 'DeepRequired<O>' is not assignable to type 'O'.
    'DeepRequired<O>' is assignable to the constraint of type 'O', but 'O' could be instantiated with a different subtype of constraint '{}'.
      Type 'O[key] extends {} ? DeepRequired<O[key]> : NonNullable<O[key]>' is not assignable to type 'O[key]'.
        Type 'DeepRequired<O[key]> | NonNullable<O[key]>' is not assignable to type 'O[key]'.
          Type 'DeepRequired<O[key]>' is not assignable to type 'O[key]'.

Playground Link:

Link

Related Issues:

#29049

@fatcerberus
Copy link

It seems that the root of the issue is that, since O is an unbound type variable, TypeScript doesn't actually know DeepRequired<O> is related to O (it does know it's related to {} but this isn't enough, as the error message proves). For that the compiler would need to do some kind of higher-level reasoning (i.e. reasoning about the generic type alias itself rather than a specific instantiation of it), which it can't currently do.

My suspicion is therefore that this is probably a design limitation.

@RyanCavanaugh RyanCavanaugh added the Design Limitation Constraints of the existing architecture prevent this from being fixed label Jun 12, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed
Projects
None yet
Development

No branches or pull requests

3 participants