-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Unstable type inference when generic is inferred from a return type #29771
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
Comments
A samller example of what you are trying to do would be: declare function useDerivedState<T>(
initializer: (previous: T ) => T
): T
const state = useDerivedState(previous => 0) // state is {} Just as an opinion, I don't think typescript can deal with this scenario well at the moment. It's probably trying to figure out the type of the callback, and to do that it needs a type for the parameter, and there is nowhere to get that from so goes with the default of |
Yeah, that is probably the central cause, but the odd thing is that the inference was so unstable and would change by just interacting with the IDE even without changing the source code. Luckily, because I only actually needed a small portion of the useDerivedState(
(previous: ReturnType<typeof deriveFoo>) =>
deriveFoo(previous !== undefined ? previous.foo.bar : undefined)
)
function deriveFoo(argument?: BarType) {
return fooFactory(argument, factoryOptions)
} |
Our inference system can't really deal with a |
Same here, which is very sad 😞 interface ServerConfig<T, U, V> {
server: () => T
startServer: (param: T) => U
stopServer: (param: U) => V
}
function config<T, U, V>(cfg: ServerConfig<T, U, V>): ServerConfig<T, U, V> {
return cfg
} Expected behavior:
ServerConfig<{ foo:'bar' }, string, number> Actual behavior: ServerConfig<{ foo:'bar' }, {}, number> The return types are sometimes inferred, sometimes not, which makes it unreliable 😢 |
Oddly, when you give the compiler less information it gets the inference correct. I don't know why this is, and perhaps is related to the "unreliability" that others were talking about: interface Apple<T> {
parse: (value: string) => T,
stringify: (value: T) => string,
};
declare function eatApple<T>(apple: Apple<T>): void
eatApple({
// infers `T` as `unknown`
parse: value => Number.parseInt(value),
// errors because `value` is `unknown`
stringify: value => value.toString(),
})
eatApple({
// infers `T` as `number`
parse: (value: string) => Number.parseInt(value),
// works because `value` is `number`
stringify: value => value.toString(),
})
interface Banana<T> {
parse: (value: string) => T
}
declare function eatBanana<T>(banana: Banana<T>): void
eatBanana({
// `T` correctly inferred as `number`
parse: value => Number.parseInt(value),
}) Of note is that an instance of |
That makes sense, though. Inference only breaks down when the generic is used in both a return type position and another position. |
TypeScript Version: 3.2.4, 3.3.1, 3.4.0-dev.20190206
Search Terms: generic return
Code
Expected behavior:
foo
exists and is accessibleActual behavior:
Very inconsistent.
This image is probably the most egregious example (
state
is{ foo: string }
):But if I then type a whitespace or something to get the compiler to update, sometimes it starts seeing
state
as{}
:There are also some cases I can't screenshot properly. For example, this is the full derivation when it is almost working correctly:
But if I cause some input to happen, the derivation might reset to
<{}>
. However, pressing command to be able to use the screenshot tool causes the tooltip to update and it goes back to the full derivation.The only thing that is consistent is that type of the
previous
argument seems to always be derived as{}
.Related Issues: #29638 and probably a bunch of others that look similar but don't quite show this odd / pathological behavior.
Giving
makeFoo
directly as the argument to the function avoids the problem but the current state is a minimum reproducible example of a problem I found that can't just be changed to that.The text was updated successfully, but these errors were encountered: