-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Functions should not be assignable to objects #27278
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
Much like how Dogs are Mammals, Functions are objects in JavaScript. They are You can write something like this to achieve something close to the desired effect: type ObjectButNotFunction = object & { prototype?: never; };
function fn(obj: ObjectButNotFunction) { }
// OK
fn({});
// Error
fn(() => { }); |
Thanks for the quick response and the hint how to define an What do you think about my second suggestion? The behavior of |
Given your explanation, I tried the following, which works: type FunctionWithProperty = (() => void) & { p?: number };
const f: FunctionWithProperty = () => { return; };
f.p = 1;
How would you create an instance if the key |
As of const f= () => { return; };
f.p = 1;
const y: (() => void) & { p: number } = f; // Works! |
@KasparEtter keyof {p:any;} works as designed. Seems like 'keyof string' just returns all members of 'String' interface. And here everything is correct keyof now returns string | number | symbol. |
Thanks a lot for all your responses! Since there exist enough open issues already, I close this one now with the following remarks and conclusions for all future readers:
|
Search Terms
function, object, type compatibility, assignment, generic constraint
Suggestion
I was surprised by the following behavior of TypeScript (as of version 3.0.3):
I searched everywhere for documentation and explanation of this behavior. The closest I could find is
from the official handbook, which kind of implies that functions are not excluded. This behavior is nevertheless surprising given the fact that even JavaScript distinguishes between object and function types (at least in case of typeof.) (Not being a JavaScript expert myself, there does seem to be a difference in JavaScript, though: In case of
let f = a => a; f.p = 1;
,f.p
evaluates to1
, whereas in case oflet v = 1; v.p = 1;
,v.p
evaluates toundefined
. This might explain why TypeScript handles functions the way it does, however, it shouldn't be relevant how JavaScript handles this, in my opinion, because such assignments don't work in TypeScript anyway.)My suggestion is to make functions non-assignable to the
object
type (which can but doesn't have to include introducing a new typefunction
(or something similar if the collision with the keyword is to be avoided) for all types that have a call signature).Use Cases
The reason I stumbled upon this behavior is that I thought about constraining the generic type of a React higher-order component with
object
(as infunction load<LoadedProps extends object, ProvidedProps extends object = {}>(…) {…}
which loads some properties from the backend but still requires other properties to be provided by the caller). At least to me, it makes sense that properties have to be objects but with the current version of TypeScript you can still writeload<(a: string) => string>(…)
(though notload<string>(…)
).Additional Suggestion
There was also another reason why I thought about constraining the generic type: I'm using
keyof LoadedProps
in the code, which also only makes sense on objects – at least to me. Using the tooltip of Visual Studio Code,keyof
has the following behavior:Wouldn't it make sense to support
keyof
only forobject
types?could (respectively with this second suggestion then should) result in a compile-time error and would have to replaced by
Feedback
If this has been asked, discussed or explained before, please refer me to the corresponding conversation or documentation. If this issue hasn't been raised before, do my suggestions make sense or is this behavior intended (and for what reasons)?
Checklist
My suggestion meets these guidelines:
I guess it doesn't have to be a breaking change in existing code if, instead of redefining
object
, we introduce a new typeobjectWithoutFunctions
(or something more elegant). (The second suggestion breaks existing code like in the given example but maybe it could still be considered for TypeScript 4.)The text was updated successfully, but these errors were encountered: