Repository navigation
Proposal: strict flag to prevent uninferrable generic types from being inferred as {} #27288
Description
Activity
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)
Klaus Meinhardt (@ajafff) Great find! My issue is a proposed solution for the same problem raised in #5254. And it looks like Daniel Rosenwasser (@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.
Reacted by Tyler Jones- addedSuggestionAn idea for TypeScriptAn idea for TypeScriptIn DiscussionNot yet reached consensusNot yet reached consensus
on Sep 24, 2018 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.
Reacted by Tyler Jones, Martin Probst, Bowen Ni and Rado Kirov- addedCommittedThe team has roadmapped this issueThe team has roadmapped this issueand removedIn DiscussionNot yet reached consensusNot yet reached consensus
on Oct 9, 2018 RyanCavanaugh commented
on Oct 9, 2018 MemberMore actionsDaniel will see what the impact of such a flag would be
Reacted by Boris Cherny, Veniamin Krol, itsMapleLeaf, David Goldstein, Stefano Pigozzi and Titian Cernicova-DragomirIt'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[]>'. }
Reacted by Tyler Jones and Tomáš SzaboOliverJAsh commented
on Feb 12, 2019 ContributorMore actionsAs an aside, why is
{}used as a fallback instead ofunknown?jack-williams commented
on Feb 12, 2019 CollaboratorMore actionsOliver Joseph Ash (@OliverJAsh) relevant comment here.
OliverJAsh commented
on Feb 13, 2019 ContributorMore actionsAnother use case: when using a
pipeorcomposefunction, generics are sometimes lost.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, )({});
- addedExperimentA fork with an experimental idea which might not make it into masterA fork with an experimental idea which might not make it into master
on Feb 15, 2019 - Reacted by Boris Cherny
RyanCavanaugh commented
on May 31, 2019 MemberMore actionsWe didn't quite implement this flag, but the new behavior of
unknownfixes the vast majority of problems associated with{}. Combined withstrictFunctionTypesand not writing generic functions which can be called with zero inference sites in the first place, I think this effectively fixed.Reacted by Veniamin Krol and Oliver Joseph AshReacted by Boris Cherny
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
strictmode 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
ris{}.If I try to fix this by adding an explicit annotate when I consume
r, it works:But if I have
strictFunctionTypesenabled, 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