Comments (4)
Here the source signature (<H extends Host2>(host: H): Page<H>
) gets instantiated in context of the target signature ((...args: any[]): IPage<Host1>
). That gets us a new source: (host: any): Page<any>
. So the problem is that the any
from the argument list in your target becomes an inference source for H
on the source side and gets picked as the inferred type. This corrupts the comparison of those 2 signatures.
An interesting thing about this is that this code path uses different logic for inference from a signature than inferFromSignature
. The latter uses the same inference priority for parameters and return types but collects covariant and contravariant candidates separately (and a covariant candidate is often preferred). This case uses different priorities (InferencePriority.ReturnType
is weaker than InferencePriority.None
) and collects everything as covariant candidates.
from typescript.
To paraphrase @Andarist, my understanding of why H
is inferred as any
is because:
H
exists in two places, as a parameter and as a return type.H
corresponds toany
in the parameter in the inference context of(...args: any[]) => IPage<Host1>
.H
could also beHost1
, buttypeof Host2Page
is invariant, and (IIUC) TS prefers the parameter type anyway, soany
is inferred overHost1
.
From this perspective, I think TS is acting as intended, and the problem is actually the misuse of (...args: any[])
which has colloquially come to mean "I don't care about the parameters", instead of what it actually means which is "Must accept any and all parameters".
The solution we found was to use a constructor type as the inference context that allows parameters and return types to be contravariant and covariant respectively, e.g.
type PageCtor<T extends IHost, TIn extends T = T, TOut extends T = T> = new (host: TIn) => IPage<TOut>
This allows TIn and TOut to be inferred independently of each other, which is usually why (...args: any[])
is used - to prevent the args from getting in the way of the return type.
Here it is in action: https://tsplay.dev/WGbO9m
I'm going to suggest that this issue is closed as 'working as intended', however @Andarist might have an opinion about whether everything is as it should be.
It's probably worth considering whether there could be a better way to express a constructor type that keeps its variance.
from typescript.
(...args: any[])
which has colloquially come to mean "I don't care about the parameters", instead of what it actually means which is "Must accept any and all parameters".
Yep, contravariance strikes again. Just like how (x: Animal) => void
doesn't mean "the parameter is some kind of animal" but rather "must accept any kind of animal"
from typescript.
This issue has been marked as "Working as Intended" and has seen no recent activity. It has been automatically closed for house-keeping purposes.
from typescript.
Related Issues (20)
- Wrong type narrowing on union type. HOT 2
- Document link for reference types and path
- object with `?:` property type, spread last --> allowed (but shouldn't) HOT 3
- Add a flag to require JS object literals to be initialized with all declared members HOT 4
- Type inference lost after spreading array with `ArrayLike` HOT 1
- Regular Expression finds HOT 4
- "This comparison appears to be unintentional" and control flow analysis with a variable updated in lambda HOT 4
- Classes static generic function return `any` type. HOT 2
- Is assignment not allowed here? HOT 2
- Editor changes overload resolution based on syntax HOT 5
- TS cache corruption leads to "error TS2590: Expression produces a union type that is too complex to represent" HOT 1
- Type alias circularly references itself (5.4 regression) HOT 1
- error TS2385: Overload signatures must all be public, private or protected. HOT 2
- `export type * ...` statements in `.d.ts` files do not work (5.4 regression) HOT 4
- HTMLFormElement disallows symbol keys HOT 5
- TypeScript language service cannot find subclass references/implementation of mixin methods
- when using ts.getJSDocTags, the value of @type is not returned. Is there any solution? HOT 2
- Compiler allows narrower method signature than implemented interface HOT 7
- Allow overload signatures to have different access levels HOT 3
- Watcher recursively watches irrelevant directories HOT 11
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from typescript.