microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
100.59k stars 12.44k forks source link

`satisfies` throws error when having more specific real types #60196

Open gentlee opened 4 hours ago

gentlee commented 4 hours ago

πŸ”Ž Search Terms

"satisfies"

πŸ•— Version & Regression Information

⏯ Playground Link

https://www.typescriptlang.org/play/?#code/C4TwDgpgBAigrhATiAPAJSgXinAdga1wHsB3XAGigAUscDiyA+WgCjAENF2BbAZwC5qASizMA3lA5c+gqpUQRecADbBBGAL4AoLQGMiuXsCgBzCMACqvJKxYBLACaDccbgCMkIzOK1Q-UBWA4RFwoMV9-SKkeAShHcgjIvwUlVUExeKhcHghBAHJs7gg87UjtDRFedmA7XgAzO0VYBGQIoA

πŸ’» Code

type Query<R = unknown, P = unknown> = (params: P) => { params: P, result: R }

const getUser = ((id: number) => {
    return {
        params: id,
        result: {id, name: 'name'}
    }
}) satisfies Query // <- Error: Type 'unknown' is not assignable to type 'number'

πŸ™ Actual behavior

tsc throws an error in satisfies line, it has conflict with real type - number, and default satisfied generic type - unknown.

πŸ™‚ Expected behavior

Should infer type and work without errors.

Additional information about the issue

Why I created a bug and not feature request - it works pretty well if just add @ts-expect-error - function type is correct, and autocomplete works pretty good (not perfect though - returned param is still not inferred and is unknown).

Another workaround is to change parameter order in Query type and provide at least param type in satisfies line, but this is a bad solution because requires changing generic type order, which can't be done easily in real project without consequences.

jcalz commented 4 hours ago

This isn't a bug.

The type Query without type arguments is (params: unknown) => { params: unknown, result: unknown }, because you gave the type parameters default type arguments of unknown. And getUser does not satisfy that because its parameter is number, and functions are contravariant in their parameter types.

Maybe you expected satisfies Query to infer the type arguments, but that's not how TypeScript works. If that's what you expected, this is a duplicate of #32794.