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
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!
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
keyis only known to satisfy the constraint ofV, butkeymight not satisfyVitself. In other words,keyis assignable to the upper bound ofV, but for this to be safe you needkeyto be assignable to all instantiations ofV, which you don't know.A concrete example:
The value
10is assignable to the constraint ofT, but it is not assignable to this particular instantiation ofT. If there was no error I would passing10where3is expected!Your example is essentially the same, except with an intermediate type variable; the same idea applies transitively though.