Typescript: Type 'K' is not assignable to type 'V (extends K)'

Created on 13 Jan 2019  Β·  3Comments  Β·  Source: microsoft/TypeScript


TypeScript Version: 3.3.0-dev.20190112


Search Terms: type generic is not assignable to type generic extends generic

Code

export const defaultTo = <T, U>(value: T, defaultValue: U) =>
  value == null ? defaultValue : value;

export const propOr = <
  K extends number | string,
  V extends K,
  T extends { [key in K]: V }
>(
  object: T,
) => (key: K, defaultValue: V = key) =>
  key == null ? defaultValue : defaultTo((object || {})[key], defaultValue);

tsconfig.json

{
  "compilerOptions": {
    "jsx": "react",
    "target": "esnext",
    "moduleResolution": "node",
    "allowSyntheticDefaultImports": true,
    "strict": true
  },
  "include": ["src/**/*"]
}

Expected behavior:

defaultValue: V = key should work without errors (even in strict mode).

Playground Link: http://www.typescriptlang.org/play/#src=export%20const%20defaultTo%20%3D%20%3CT%2C%20U%3E(value%3A%20T%2C%20defaultValue%3A%20U)%20%3D%3E%0D%0A%20%20value%20%3D%3D%20null%20%3F%20defaultValue%20%3A%20value%3B%0D%0A%0D%0Aexport%20const%20propOr%20%3D%20%3C%0D%0A%20%20K%20extends%20number%20%7C%20string%2C%0D%0A%20%20V%20extends%20K%2C%0D%0A%20%20T%20extends%20%7B%20%5Bkey%20in%20K%5D%3A%20V%20%7D%0D%0A%3E(%0D%0A%20%20object%3A%20T%2C%0D%0A)%20%3D%3E%20(key%3A%20K%2C%20defaultValue%3A%20V%20%3D%20key)%20%3D%3E%0D%0A%20%20key%20%3D%3D%20null%20%3F%20defaultValue%20%3A%20defaultTo((object%20%7C%7C%20%7B%7D)%5Bkey%5D%2C%20defaultValue)%3B

Most helpful comment

The error message is correct here, but the error could be improved and this is tracked by #29049.

The reason why the error is correct is because key is only known to satisfy the constraint of V, but key might not satisfy V itself. In other words, key is assignable to the upper bound of V, but for this to be safe you need key to be assignable to all instantiations of V, which you don't know.

A concrete example:

function example<T extends number>(x: T = 10) {
    return;
}

example<3>();

The value 10 is assignable to the constraint of T, but it is not assignable to this particular instantiation of T. If there was no error I would passing 10 where 3 is expected!

Your example is essentially the same, except with an intermediate type variable; the same idea applies transitively though.

function example2<T extends number, U extends T>(x: T, y: U = x) {
    return;
}

example2<number, 3>(10);

All 3 comments

The error message is correct here, but the error could be improved and this is tracked by #29049.

The reason why the error is correct is because key is only known to satisfy the constraint of V, but key might not satisfy V itself. In other words, key is assignable to the upper bound of V, but for this to be safe you need key to be assignable to all instantiations of V, which you don't know.

A concrete example:

function example<T extends number>(x: T = 10) {
    return;
}

example<3>();

The value 10 is assignable to the constraint of T, but it is not assignable to this particular instantiation of T. If there was no error I would passing 10 where 3 is expected!

Your example is essentially the same, except with an intermediate type variable; the same idea applies transitively though.

function example2<T extends number, U extends T>(x: T, y: U = x) {
    return;
}

example2<number, 3>(10);

@jack-williams Thank you for the explanation, I'm closing this issue.

@kripod No problem!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

fwanicka picture fwanicka  Β·  3Comments

DanielRosenwasser picture DanielRosenwasser  Β·  3Comments

blendsdk picture blendsdk  Β·  3Comments

kyasbal-1994 picture kyasbal-1994  Β·  3Comments

manekinekko picture manekinekko  Β·  3Comments