-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Proposal: strict flag to prevent uninferrable generic types from being inferred as {} #27288
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Comments
In the meantime you can use a lint rule to detect such cases: https://github.com/fimbullinter/wotan/blob/master/packages/mimir/docs/no-inferred-empty-object.md |
IIRC there was a PR for such a flag, but it was not accepted for whatever reason. I cannot find it anymore |
I found it by accident: Duplicate of #5254, relevant comment: #5254 (comment) |
@ajafff Great find! My issue is a proposed solution for the same problem raised in #5254. And it looks like @DanielRosenwasser already started working on it a while back e21f7cf. If TypeScript authors feel like it's a good idea, I'd love to continue Daniel's work with a fully fleshed out PR. |
I think we (Google) would be interested in using this. bcherny's description about it makes errors with strictFunctionTypes non-local is exactly our experience. |
Daniel will see what the impact of such a flag would be |
It's exciting to see this committed for 3.4! One more use case, for record-keeping: function ReactComponent() {
const [boolean, setBoolean] = useState(true) // ok
setBoolean(false) // ok
const [array, setArray] = useState([])
setArray([1, 2, 3]) // Error TS2345: Argument of type 'number[]' is not assignable to parameter of type 'SetStateAction<never[]>'.
} |
As an aside, why is |
@OliverJAsh relevant comment here. |
Another use case: when using a declare const identity: <T>(a: T) => T;
declare const pipe: <A, B>(ab: (a: A) => B) => (a: A) => B;
const fn = pipe(identity); // generics lost, now {} => {} I run into this very often when trying to compose my React HOCs: declare const pipe: <A, B, C>(ab: (a: A) => B, bc: (b: B) => C) => (a: A) => C;
type Component<P> = (props: P) => {};
declare const myHoc1: <P>(C: Component<P>) => Component<P>;
declare const myHoc2: <P>(C: Component<P>) => Component<P>;
declare const MyComponent1: Component<{ foo: 1 }>;
// generics lost, now Component<{}>
const MyComponent2 = pipe(
myHoc1,
myHoc2,
)(MyComponent1); IIUC, this particular use case concerns #12838 and #10247. However, with the option proposed here, TypeScript would at least alert the developer to change the code to workaround this problem, to something like: // Component<{ foo: 1 }>
const MyComponent2 = pipe(
() => myHoc1(MyComponent1),
myHoc2,
)({}); |
We didn't quite implement this flag, but the new behavior of |
I'm sure there an issue or discussion about this I missed, but I couldn't find it via search.
Search Terms
Generic, infer, default, {}, { }, empty, shape, object
Suggestion
Behind a new
strict
mode flag--strictGenericBindings
, when binding concrete types to generic type parameters, if a type can't be inferred TSC should throw an error at compile time instead of defaulting to{}
.Use Cases
Let's say you have the following Promise:
This gives an error when you try to use the Promise's result. This experience isn't ideal, because the error is non-local. Looking at the code that threw that error, it's not obvious why
r
is{}
.If I try to fix this by adding an explicit annotate when I consume
r
, it works:But if I have
strictFunctionTypes
enabled, that breaks because{}
isn't assignable tonumber
:The real fix is to explicitly bind a type parameter when I consume
Promise
:But unfortunately, the error messages didn't help me get there.
A possible solution to this problem is to throw a helpful error message when a generic type parameter can't be inferred. This can help prevent bugs, and help programmers catch bugs earlier:
Checklist
My suggestion meets these guidelines:
Related Issues
The text was updated successfully, but these errors were encountered: