Typescript Function/Object parameters
Why is typescript ES6 not detecting that objects are not functions?
find: (collection: string, query: object, sortQuery = {}, cb?: Function) => {
socketManager.call('find', collection, query, sortQuery, cb);
}
Based off this function, you would assume that this would fail:
this._services._socket.methods.find('vendors', {type: 'repair'}, (errVen, resVen) => {}
Since there is no sortQuery object but instead a callback function. This is not giving me any type of error and means that typescript is allowing the callback as the object type.
How do I ensure this results in an error?
javascript typescript
|
show 1 more comment
Why is typescript ES6 not detecting that objects are not functions?
find: (collection: string, query: object, sortQuery = {}, cb?: Function) => {
socketManager.call('find', collection, query, sortQuery, cb);
}
Based off this function, you would assume that this would fail:
this._services._socket.methods.find('vendors', {type: 'repair'}, (errVen, resVen) => {}
Since there is no sortQuery object but instead a callback function. This is not giving me any type of error and means that typescript is allowing the callback as the object type.
How do I ensure this results in an error?
javascript typescript
Does it actually infer thesortQueryas an object type? or is it any?
– Jonas Wilms
Nov 27 '18 at 16:37
The same happens here, probably because functions are objects in JavaScript: typescriptlang.org/play/…
– Frank Modica
Nov 27 '18 at 16:38
Same results with this: find: (collection: string, query: object, sortQuery: object, cb?: Function) => { socketManager.call('find', collection, query, sortQuery, cb); }
– user1779362
Nov 27 '18 at 16:39
Any way to ensure 'Function' type and not an object?
– user1779362
Nov 27 '18 at 16:40
2
Do you know the parameters and return types of thesortQuery? You could define it more specifically
– Frank Modica
Nov 27 '18 at 16:44
|
show 1 more comment
Why is typescript ES6 not detecting that objects are not functions?
find: (collection: string, query: object, sortQuery = {}, cb?: Function) => {
socketManager.call('find', collection, query, sortQuery, cb);
}
Based off this function, you would assume that this would fail:
this._services._socket.methods.find('vendors', {type: 'repair'}, (errVen, resVen) => {}
Since there is no sortQuery object but instead a callback function. This is not giving me any type of error and means that typescript is allowing the callback as the object type.
How do I ensure this results in an error?
javascript typescript
Why is typescript ES6 not detecting that objects are not functions?
find: (collection: string, query: object, sortQuery = {}, cb?: Function) => {
socketManager.call('find', collection, query, sortQuery, cb);
}
Based off this function, you would assume that this would fail:
this._services._socket.methods.find('vendors', {type: 'repair'}, (errVen, resVen) => {}
Since there is no sortQuery object but instead a callback function. This is not giving me any type of error and means that typescript is allowing the callback as the object type.
How do I ensure this results in an error?
javascript typescript
javascript typescript
asked Nov 27 '18 at 16:33
user1779362user1779362
387213
387213
Does it actually infer thesortQueryas an object type? or is it any?
– Jonas Wilms
Nov 27 '18 at 16:37
The same happens here, probably because functions are objects in JavaScript: typescriptlang.org/play/…
– Frank Modica
Nov 27 '18 at 16:38
Same results with this: find: (collection: string, query: object, sortQuery: object, cb?: Function) => { socketManager.call('find', collection, query, sortQuery, cb); }
– user1779362
Nov 27 '18 at 16:39
Any way to ensure 'Function' type and not an object?
– user1779362
Nov 27 '18 at 16:40
2
Do you know the parameters and return types of thesortQuery? You could define it more specifically
– Frank Modica
Nov 27 '18 at 16:44
|
show 1 more comment
Does it actually infer thesortQueryas an object type? or is it any?
– Jonas Wilms
Nov 27 '18 at 16:37
The same happens here, probably because functions are objects in JavaScript: typescriptlang.org/play/…
– Frank Modica
Nov 27 '18 at 16:38
Same results with this: find: (collection: string, query: object, sortQuery: object, cb?: Function) => { socketManager.call('find', collection, query, sortQuery, cb); }
– user1779362
Nov 27 '18 at 16:39
Any way to ensure 'Function' type and not an object?
– user1779362
Nov 27 '18 at 16:40
2
Do you know the parameters and return types of thesortQuery? You could define it more specifically
– Frank Modica
Nov 27 '18 at 16:44
Does it actually infer the
sortQuery as an object type? or is it any?– Jonas Wilms
Nov 27 '18 at 16:37
Does it actually infer the
sortQuery as an object type? or is it any?– Jonas Wilms
Nov 27 '18 at 16:37
The same happens here, probably because functions are objects in JavaScript: typescriptlang.org/play/…
– Frank Modica
Nov 27 '18 at 16:38
The same happens here, probably because functions are objects in JavaScript: typescriptlang.org/play/…
– Frank Modica
Nov 27 '18 at 16:38
Same results with this: find: (collection: string, query: object, sortQuery: object, cb?: Function) => { socketManager.call('find', collection, query, sortQuery, cb); }
– user1779362
Nov 27 '18 at 16:39
Same results with this: find: (collection: string, query: object, sortQuery: object, cb?: Function) => { socketManager.call('find', collection, query, sortQuery, cb); }
– user1779362
Nov 27 '18 at 16:39
Any way to ensure 'Function' type and not an object?
– user1779362
Nov 27 '18 at 16:40
Any way to ensure 'Function' type and not an object?
– user1779362
Nov 27 '18 at 16:40
2
2
Do you know the parameters and return types of the
sortQuery? You could define it more specifically– Frank Modica
Nov 27 '18 at 16:44
Do you know the parameters and return types of the
sortQuery? You could define it more specifically– Frank Modica
Nov 27 '18 at 16:44
|
show 1 more comment
2 Answers
2
active
oldest
votes
With TypeScript Conditionals (TS v2.8), we can use Exclude to exclude Functions from the object type using Exclude<T, Function>:
let v = {
find: <T extends object>(collection: string, query: object, sortQuery: Exclude<T, Function>, cb?: (a: string, b: string) => void) => {
}
}
// Invalid
v.find('vendors', { type: 'repair' }, (a, b) => { })
v.find('vendors', { type: 'repair' }, 'I am a string', (a, b) => { })
// Valid
v.find('vendors', { type: 'repair' }, { dir: -1 })
v.find('vendors', { type: 'repair' }, { dir: -1 }, (a, b) => { })
A default parameter value can then be set like this:
sortQuery: Exclude<T, Function> = <any>{}
As you can see in the image below, errors are thrown for the first two calls to find, but not the second two calls to find:

The errors that then display are as follows:
- [ts] Argument of type '(a, b) => void' is not assignable to parameter of type 'never'. [2345]
- [ts] Argument of type '"I am a string"' is not assignable to parameter of type 'object'. [2345]
This is a great solution. So one thing I didn't mention is that I have a script which is running through all my server functions and parsing through the files to grab the function names and the parameters to generate the functions on the client side. Would it be ok if I changed my script to do this on all functions?
– user1779362
Nov 27 '18 at 18:19
find: <T extends object>(collection: string, query: object, sortQuery: Exclude<T, Function> = <any>{}, cb?: Function) => { socketManager.call('find', collection, query, sortQuery, cb); }, findWithOptions: (collection: string, query: object, options: PaginationOptions, cb?: Function) => { socketManager.call('findWithOptions', collection, query, options, cb); }, insertDocument: (collection: string, document: object, cb?: Function) => { socketManager.call('insertDocument', collection, document, cb); },
– user1779362
Nov 27 '18 at 18:20
I don't know why you couldn't...
– Get Off My Lawn
Nov 27 '18 at 18:22
add a comment |
Objects and functions are fundamentally the same thing, but typings help us disambiguate between their functionality.
Consider this:
const foo1: { (): string } = () => "";
The variable foo has a type of object, but that object is callable ... it's a function, and it can indeed be called, but you can't go setting a property called bar on it.
foo1(); // This works
foo1.bar = 5; // This, not so much.
Also consider this:
const foo2: { bar?: number; } = {};
The variable foo has a property called bar on it. That property can be set, but the object can't be called, as it's not typed as callable.
foo2.bar = 5; // This works
foo2(); // This, not so much.
So, lets have a look at your original typing:
sortQuery = {}
sortQuery is an object, but that's all that we know about it. It doesn't have any properties, it's not callable, it's just an object.
We've already seen that a function is an object, so you can assign a function to it just fine. But, you won't be able to call it, as it's not defined as callable.
const sortQuery: {} = () => ""; // This works.
sortQuery(); // This, not so much.
sortQuery.bar = 5; // Nor this.
If you have full control of the source code, then one way to solve this is to move from multiple parameters, to a single parameter with named properties:
const foo = (params: { collection: string, query: object, sortQuery: {}, cb?: Function }) => { };
foo({ collection: "", query: {}, sortQuery: {} }); // Fine
foo({ collection: "", query: {}, sortQuery: {}, cb: () => { } }); // Fine
foo({ collection: "", query: {}, cb: () => { } }); // Not Fine
This removes any ambiguity by requiring names, rather than relying on position in the function call.
1
This is also a good solution to use objects. Unfortunately this would take a considerable amount of time to rework all the calls / create a script to fix all this. Good answer though.
– user1779362
Nov 27 '18 at 18:22
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53504160%2ftypescript-function-object-parameters%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
With TypeScript Conditionals (TS v2.8), we can use Exclude to exclude Functions from the object type using Exclude<T, Function>:
let v = {
find: <T extends object>(collection: string, query: object, sortQuery: Exclude<T, Function>, cb?: (a: string, b: string) => void) => {
}
}
// Invalid
v.find('vendors', { type: 'repair' }, (a, b) => { })
v.find('vendors', { type: 'repair' }, 'I am a string', (a, b) => { })
// Valid
v.find('vendors', { type: 'repair' }, { dir: -1 })
v.find('vendors', { type: 'repair' }, { dir: -1 }, (a, b) => { })
A default parameter value can then be set like this:
sortQuery: Exclude<T, Function> = <any>{}
As you can see in the image below, errors are thrown for the first two calls to find, but not the second two calls to find:

The errors that then display are as follows:
- [ts] Argument of type '(a, b) => void' is not assignable to parameter of type 'never'. [2345]
- [ts] Argument of type '"I am a string"' is not assignable to parameter of type 'object'. [2345]
This is a great solution. So one thing I didn't mention is that I have a script which is running through all my server functions and parsing through the files to grab the function names and the parameters to generate the functions on the client side. Would it be ok if I changed my script to do this on all functions?
– user1779362
Nov 27 '18 at 18:19
find: <T extends object>(collection: string, query: object, sortQuery: Exclude<T, Function> = <any>{}, cb?: Function) => { socketManager.call('find', collection, query, sortQuery, cb); }, findWithOptions: (collection: string, query: object, options: PaginationOptions, cb?: Function) => { socketManager.call('findWithOptions', collection, query, options, cb); }, insertDocument: (collection: string, document: object, cb?: Function) => { socketManager.call('insertDocument', collection, document, cb); },
– user1779362
Nov 27 '18 at 18:20
I don't know why you couldn't...
– Get Off My Lawn
Nov 27 '18 at 18:22
add a comment |
With TypeScript Conditionals (TS v2.8), we can use Exclude to exclude Functions from the object type using Exclude<T, Function>:
let v = {
find: <T extends object>(collection: string, query: object, sortQuery: Exclude<T, Function>, cb?: (a: string, b: string) => void) => {
}
}
// Invalid
v.find('vendors', { type: 'repair' }, (a, b) => { })
v.find('vendors', { type: 'repair' }, 'I am a string', (a, b) => { })
// Valid
v.find('vendors', { type: 'repair' }, { dir: -1 })
v.find('vendors', { type: 'repair' }, { dir: -1 }, (a, b) => { })
A default parameter value can then be set like this:
sortQuery: Exclude<T, Function> = <any>{}
As you can see in the image below, errors are thrown for the first two calls to find, but not the second two calls to find:

The errors that then display are as follows:
- [ts] Argument of type '(a, b) => void' is not assignable to parameter of type 'never'. [2345]
- [ts] Argument of type '"I am a string"' is not assignable to parameter of type 'object'. [2345]
This is a great solution. So one thing I didn't mention is that I have a script which is running through all my server functions and parsing through the files to grab the function names and the parameters to generate the functions on the client side. Would it be ok if I changed my script to do this on all functions?
– user1779362
Nov 27 '18 at 18:19
find: <T extends object>(collection: string, query: object, sortQuery: Exclude<T, Function> = <any>{}, cb?: Function) => { socketManager.call('find', collection, query, sortQuery, cb); }, findWithOptions: (collection: string, query: object, options: PaginationOptions, cb?: Function) => { socketManager.call('findWithOptions', collection, query, options, cb); }, insertDocument: (collection: string, document: object, cb?: Function) => { socketManager.call('insertDocument', collection, document, cb); },
– user1779362
Nov 27 '18 at 18:20
I don't know why you couldn't...
– Get Off My Lawn
Nov 27 '18 at 18:22
add a comment |
With TypeScript Conditionals (TS v2.8), we can use Exclude to exclude Functions from the object type using Exclude<T, Function>:
let v = {
find: <T extends object>(collection: string, query: object, sortQuery: Exclude<T, Function>, cb?: (a: string, b: string) => void) => {
}
}
// Invalid
v.find('vendors', { type: 'repair' }, (a, b) => { })
v.find('vendors', { type: 'repair' }, 'I am a string', (a, b) => { })
// Valid
v.find('vendors', { type: 'repair' }, { dir: -1 })
v.find('vendors', { type: 'repair' }, { dir: -1 }, (a, b) => { })
A default parameter value can then be set like this:
sortQuery: Exclude<T, Function> = <any>{}
As you can see in the image below, errors are thrown for the first two calls to find, but not the second two calls to find:

The errors that then display are as follows:
- [ts] Argument of type '(a, b) => void' is not assignable to parameter of type 'never'. [2345]
- [ts] Argument of type '"I am a string"' is not assignable to parameter of type 'object'. [2345]
With TypeScript Conditionals (TS v2.8), we can use Exclude to exclude Functions from the object type using Exclude<T, Function>:
let v = {
find: <T extends object>(collection: string, query: object, sortQuery: Exclude<T, Function>, cb?: (a: string, b: string) => void) => {
}
}
// Invalid
v.find('vendors', { type: 'repair' }, (a, b) => { })
v.find('vendors', { type: 'repair' }, 'I am a string', (a, b) => { })
// Valid
v.find('vendors', { type: 'repair' }, { dir: -1 })
v.find('vendors', { type: 'repair' }, { dir: -1 }, (a, b) => { })
A default parameter value can then be set like this:
sortQuery: Exclude<T, Function> = <any>{}
As you can see in the image below, errors are thrown for the first two calls to find, but not the second two calls to find:

The errors that then display are as follows:
- [ts] Argument of type '(a, b) => void' is not assignable to parameter of type 'never'. [2345]
- [ts] Argument of type '"I am a string"' is not assignable to parameter of type 'object'. [2345]
edited Nov 27 '18 at 18:21
answered Nov 27 '18 at 17:34
Get Off My LawnGet Off My Lawn
13.6k1783176
13.6k1783176
This is a great solution. So one thing I didn't mention is that I have a script which is running through all my server functions and parsing through the files to grab the function names and the parameters to generate the functions on the client side. Would it be ok if I changed my script to do this on all functions?
– user1779362
Nov 27 '18 at 18:19
find: <T extends object>(collection: string, query: object, sortQuery: Exclude<T, Function> = <any>{}, cb?: Function) => { socketManager.call('find', collection, query, sortQuery, cb); }, findWithOptions: (collection: string, query: object, options: PaginationOptions, cb?: Function) => { socketManager.call('findWithOptions', collection, query, options, cb); }, insertDocument: (collection: string, document: object, cb?: Function) => { socketManager.call('insertDocument', collection, document, cb); },
– user1779362
Nov 27 '18 at 18:20
I don't know why you couldn't...
– Get Off My Lawn
Nov 27 '18 at 18:22
add a comment |
This is a great solution. So one thing I didn't mention is that I have a script which is running through all my server functions and parsing through the files to grab the function names and the parameters to generate the functions on the client side. Would it be ok if I changed my script to do this on all functions?
– user1779362
Nov 27 '18 at 18:19
find: <T extends object>(collection: string, query: object, sortQuery: Exclude<T, Function> = <any>{}, cb?: Function) => { socketManager.call('find', collection, query, sortQuery, cb); }, findWithOptions: (collection: string, query: object, options: PaginationOptions, cb?: Function) => { socketManager.call('findWithOptions', collection, query, options, cb); }, insertDocument: (collection: string, document: object, cb?: Function) => { socketManager.call('insertDocument', collection, document, cb); },
– user1779362
Nov 27 '18 at 18:20
I don't know why you couldn't...
– Get Off My Lawn
Nov 27 '18 at 18:22
This is a great solution. So one thing I didn't mention is that I have a script which is running through all my server functions and parsing through the files to grab the function names and the parameters to generate the functions on the client side. Would it be ok if I changed my script to do this on all functions?
– user1779362
Nov 27 '18 at 18:19
This is a great solution. So one thing I didn't mention is that I have a script which is running through all my server functions and parsing through the files to grab the function names and the parameters to generate the functions on the client side. Would it be ok if I changed my script to do this on all functions?
– user1779362
Nov 27 '18 at 18:19
find: <T extends object>(collection: string, query: object, sortQuery: Exclude<T, Function> = <any>{}, cb?: Function) => { socketManager.call('find', collection, query, sortQuery, cb); }, findWithOptions: (collection: string, query: object, options: PaginationOptions, cb?: Function) => { socketManager.call('findWithOptions', collection, query, options, cb); }, insertDocument: (collection: string, document: object, cb?: Function) => { socketManager.call('insertDocument', collection, document, cb); },
– user1779362
Nov 27 '18 at 18:20
find: <T extends object>(collection: string, query: object, sortQuery: Exclude<T, Function> = <any>{}, cb?: Function) => { socketManager.call('find', collection, query, sortQuery, cb); }, findWithOptions: (collection: string, query: object, options: PaginationOptions, cb?: Function) => { socketManager.call('findWithOptions', collection, query, options, cb); }, insertDocument: (collection: string, document: object, cb?: Function) => { socketManager.call('insertDocument', collection, document, cb); },
– user1779362
Nov 27 '18 at 18:20
I don't know why you couldn't...
– Get Off My Lawn
Nov 27 '18 at 18:22
I don't know why you couldn't...
– Get Off My Lawn
Nov 27 '18 at 18:22
add a comment |
Objects and functions are fundamentally the same thing, but typings help us disambiguate between their functionality.
Consider this:
const foo1: { (): string } = () => "";
The variable foo has a type of object, but that object is callable ... it's a function, and it can indeed be called, but you can't go setting a property called bar on it.
foo1(); // This works
foo1.bar = 5; // This, not so much.
Also consider this:
const foo2: { bar?: number; } = {};
The variable foo has a property called bar on it. That property can be set, but the object can't be called, as it's not typed as callable.
foo2.bar = 5; // This works
foo2(); // This, not so much.
So, lets have a look at your original typing:
sortQuery = {}
sortQuery is an object, but that's all that we know about it. It doesn't have any properties, it's not callable, it's just an object.
We've already seen that a function is an object, so you can assign a function to it just fine. But, you won't be able to call it, as it's not defined as callable.
const sortQuery: {} = () => ""; // This works.
sortQuery(); // This, not so much.
sortQuery.bar = 5; // Nor this.
If you have full control of the source code, then one way to solve this is to move from multiple parameters, to a single parameter with named properties:
const foo = (params: { collection: string, query: object, sortQuery: {}, cb?: Function }) => { };
foo({ collection: "", query: {}, sortQuery: {} }); // Fine
foo({ collection: "", query: {}, sortQuery: {}, cb: () => { } }); // Fine
foo({ collection: "", query: {}, cb: () => { } }); // Not Fine
This removes any ambiguity by requiring names, rather than relying on position in the function call.
1
This is also a good solution to use objects. Unfortunately this would take a considerable amount of time to rework all the calls / create a script to fix all this. Good answer though.
– user1779362
Nov 27 '18 at 18:22
add a comment |
Objects and functions are fundamentally the same thing, but typings help us disambiguate between their functionality.
Consider this:
const foo1: { (): string } = () => "";
The variable foo has a type of object, but that object is callable ... it's a function, and it can indeed be called, but you can't go setting a property called bar on it.
foo1(); // This works
foo1.bar = 5; // This, not so much.
Also consider this:
const foo2: { bar?: number; } = {};
The variable foo has a property called bar on it. That property can be set, but the object can't be called, as it's not typed as callable.
foo2.bar = 5; // This works
foo2(); // This, not so much.
So, lets have a look at your original typing:
sortQuery = {}
sortQuery is an object, but that's all that we know about it. It doesn't have any properties, it's not callable, it's just an object.
We've already seen that a function is an object, so you can assign a function to it just fine. But, you won't be able to call it, as it's not defined as callable.
const sortQuery: {} = () => ""; // This works.
sortQuery(); // This, not so much.
sortQuery.bar = 5; // Nor this.
If you have full control of the source code, then one way to solve this is to move from multiple parameters, to a single parameter with named properties:
const foo = (params: { collection: string, query: object, sortQuery: {}, cb?: Function }) => { };
foo({ collection: "", query: {}, sortQuery: {} }); // Fine
foo({ collection: "", query: {}, sortQuery: {}, cb: () => { } }); // Fine
foo({ collection: "", query: {}, cb: () => { } }); // Not Fine
This removes any ambiguity by requiring names, rather than relying on position in the function call.
1
This is also a good solution to use objects. Unfortunately this would take a considerable amount of time to rework all the calls / create a script to fix all this. Good answer though.
– user1779362
Nov 27 '18 at 18:22
add a comment |
Objects and functions are fundamentally the same thing, but typings help us disambiguate between their functionality.
Consider this:
const foo1: { (): string } = () => "";
The variable foo has a type of object, but that object is callable ... it's a function, and it can indeed be called, but you can't go setting a property called bar on it.
foo1(); // This works
foo1.bar = 5; // This, not so much.
Also consider this:
const foo2: { bar?: number; } = {};
The variable foo has a property called bar on it. That property can be set, but the object can't be called, as it's not typed as callable.
foo2.bar = 5; // This works
foo2(); // This, not so much.
So, lets have a look at your original typing:
sortQuery = {}
sortQuery is an object, but that's all that we know about it. It doesn't have any properties, it's not callable, it's just an object.
We've already seen that a function is an object, so you can assign a function to it just fine. But, you won't be able to call it, as it's not defined as callable.
const sortQuery: {} = () => ""; // This works.
sortQuery(); // This, not so much.
sortQuery.bar = 5; // Nor this.
If you have full control of the source code, then one way to solve this is to move from multiple parameters, to a single parameter with named properties:
const foo = (params: { collection: string, query: object, sortQuery: {}, cb?: Function }) => { };
foo({ collection: "", query: {}, sortQuery: {} }); // Fine
foo({ collection: "", query: {}, sortQuery: {}, cb: () => { } }); // Fine
foo({ collection: "", query: {}, cb: () => { } }); // Not Fine
This removes any ambiguity by requiring names, rather than relying on position in the function call.
Objects and functions are fundamentally the same thing, but typings help us disambiguate between their functionality.
Consider this:
const foo1: { (): string } = () => "";
The variable foo has a type of object, but that object is callable ... it's a function, and it can indeed be called, but you can't go setting a property called bar on it.
foo1(); // This works
foo1.bar = 5; // This, not so much.
Also consider this:
const foo2: { bar?: number; } = {};
The variable foo has a property called bar on it. That property can be set, but the object can't be called, as it's not typed as callable.
foo2.bar = 5; // This works
foo2(); // This, not so much.
So, lets have a look at your original typing:
sortQuery = {}
sortQuery is an object, but that's all that we know about it. It doesn't have any properties, it's not callable, it's just an object.
We've already seen that a function is an object, so you can assign a function to it just fine. But, you won't be able to call it, as it's not defined as callable.
const sortQuery: {} = () => ""; // This works.
sortQuery(); // This, not so much.
sortQuery.bar = 5; // Nor this.
If you have full control of the source code, then one way to solve this is to move from multiple parameters, to a single parameter with named properties:
const foo = (params: { collection: string, query: object, sortQuery: {}, cb?: Function }) => { };
foo({ collection: "", query: {}, sortQuery: {} }); // Fine
foo({ collection: "", query: {}, sortQuery: {}, cb: () => { } }); // Fine
foo({ collection: "", query: {}, cb: () => { } }); // Not Fine
This removes any ambiguity by requiring names, rather than relying on position in the function call.
edited Nov 27 '18 at 17:27
answered Nov 27 '18 at 17:14
AndyJAndyJ
4,79923467
4,79923467
1
This is also a good solution to use objects. Unfortunately this would take a considerable amount of time to rework all the calls / create a script to fix all this. Good answer though.
– user1779362
Nov 27 '18 at 18:22
add a comment |
1
This is also a good solution to use objects. Unfortunately this would take a considerable amount of time to rework all the calls / create a script to fix all this. Good answer though.
– user1779362
Nov 27 '18 at 18:22
1
1
This is also a good solution to use objects. Unfortunately this would take a considerable amount of time to rework all the calls / create a script to fix all this. Good answer though.
– user1779362
Nov 27 '18 at 18:22
This is also a good solution to use objects. Unfortunately this would take a considerable amount of time to rework all the calls / create a script to fix all this. Good answer though.
– user1779362
Nov 27 '18 at 18:22
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53504160%2ftypescript-function-object-parameters%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Does it actually infer the
sortQueryas an object type? or is it any?– Jonas Wilms
Nov 27 '18 at 16:37
The same happens here, probably because functions are objects in JavaScript: typescriptlang.org/play/…
– Frank Modica
Nov 27 '18 at 16:38
Same results with this: find: (collection: string, query: object, sortQuery: object, cb?: Function) => { socketManager.call('find', collection, query, sortQuery, cb); }
– user1779362
Nov 27 '18 at 16:39
Any way to ensure 'Function' type and not an object?
– user1779362
Nov 27 '18 at 16:40
2
Do you know the parameters and return types of the
sortQuery? You could define it more specifically– Frank Modica
Nov 27 '18 at 16:44