-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
Proposal: strict flag to prevent uninferrable generic types from being inferred as {} #27288
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: