-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Using inferred return type of function as argument to same function breaks type inference #26228
Comments
Can you boil this down to a standalone example? Just trimming down things from the linked file until there's nothing that doesn't need to be there should be enough. Thanks! |
It took me forever, but I finally found a minimal example, type AssertDelegate<T> = (name: string, mixed: unknown) => T;
class Field<NameT extends string, AssertT extends AssertDelegate<any>> {
constructor(
readonly name: NameT,
readonly assertDelegate : AssertT
) {}
}
type TypeOf<FieldT extends Field<any, any>> = (
ReturnType<FieldT["assertDelegate"]>
);
declare function schema<FieldT extends Field<any, any>> (fields : FieldT) : (
AssertDelegate<{
[k in FieldT["name"]] : TypeOf<FieldT>
}>
);
declare const assertBoolean: AssertDelegate<boolean>;
const obj = schema(
new Field("z", assertBoolean)
);
const objField = new Field("obj", obj);
//Incorrect;
//AssertDelegate<{ obj: any; }>
const actualTypeOfNested = schema(
objField
);
//OK;
//(name: string, mixed: unknown) => { obj: { z: boolean; }; }
//Or,
//AssertDelegate<{ obj: { z: boolean; }; }>
type expectedTypeOfNested = AssertDelegate<{
[k in typeof objField["name"]] : TypeOf<typeof objField>
}>
//COPY PASTE of schema<>()
declare function schema2<FieldT extends Field<any, any>> (fields : FieldT) : (
AssertDelegate<{
[k in FieldT["name"]] : TypeOf<FieldT>
}>
);
//OK;
//AssertDelegate<{ obj: { z: boolean; }; }>
//WTF?
const actualTypeOfNested2 = schema2(
objField
);
//I swear there is some kind of short-circuiting happening here.
//Oh, you are trying to call `foo(foo(/*arg*/))`?
//I'm too lazy, I'll just say the return type is `any`.
//But if you copy-paste and make it,
//`foo2(foo(/*arg*/))`,
//TS goes, "Oh, okay, it's extra work but I'll do it properly" I have all the checkboxes ticked in the This behaviour is breaking my data validation library that has to validate the data type and value of nested objects in a multitude of ways. Right now, run-time validation works correctly but compile-time checks break because it infers |
I just played with it a bit more. declare function schema<T> (value : T) : (
{
field : T
}
);
declare const b: boolean;
//OK;
//Inferred { field : boolean }
const obj = schema(b);
//Incorrect;
//Inferred { field : any }
//Expected { field : { field : boolean } }
const actualTypeOfNested = schema(obj);
//Gives an error, as expected,
//Type 'boolean' is not assignable to type 'number'
const n: number = actualTypeOfNested.field.field;
//OK
const b2: boolean = actualTypeOfNested.field.field;
//Gives an error, as expected,
//Type 'boolean' is not assignable to type 'number'
const notAssignable: { field: { field: number } } = actualTypeOfNested;
//OK
const assignable: { field: { field: boolean } } = actualTypeOfNested; So, it looks like the tooltip that gives the type inference is short-circuiting or something and just giving So, it seems like it's somewhat related to #26238 In TS 3.0.1 with VS code (and on the Playground editor), all of a sudden, the tooltip that's supposed to give the inferred type is truncating text, and it looks like it also gives Is there any way I can get it to just display the full type truthfully, without it truncating, or giving up and displaying I remember, in TS 2.9, there wasn't truncation on the tooltip displaying inferred types. |
Fix bugs in the compiler 😉 |
@weswigham type display issue |
I've tried to look at the source code a few times, cursory glances only, and it just goes over my head. Hopefully I can figure this all out at some point. |
TypeScript Version: 3.0.1
Search Terms: return type inference
Code
My specific instance of this problem can be found here
Scroll to the very bottom to see a comment about it.
I couldn't figure out a minimal example but it looks like,
However, if I explicitly declare the type of
result1
, it works,Or, if I do this very weird thing,
Trying a type alias fails,
But this also works,
It seems like if I rely on return type inference, I have to copy-paste the function type, and cannot re-use a previous declaration.
So, if I wanted to nest the results 4 times, I'd need
foo1, foo2, foo3, foo4
Right now, I just either declare the return-type explicitly, every time the function is used, or I don't use the function at all.
Expected behavior:
Inferred type to not have
any
Actual behavior:
Inferred type contains
any
The text was updated successfully, but these errors were encountered: