Overloading a recursive function in Typescript with Array and TypedArray












0















I have a recursive function with 2 overloads :



export function select(
array: Float32Array,
first: number,
nth: number,
last: number,
comp: (a: number, b: number) => boolean,
): void;
export function select<T>(
array: T,
first: number,
nth: number,
last: number,
comp: (a: T, b: T) => boolean,
): void;
export function select<T>(
array: Float32Array | T,
first: number,
nth: number,
last: number,
comp: (a: number | T, b: number | T) => boolean,
): void {
// Implementation of Floyd-Rivest algorithm
// Some code
select(array, newFirst, nth, newLast, comp);
// Some code
}


Typescript complains about variable array when calling select function recursively in the implementation :




The argument of type 'Float32Array | T' is not assignable to the parameter of type '(number | T)'.




First, I don't really understand why typescript try to compare the type of argument array with a type (number | T) which does not exist in the different signatures. Does it try to compare the type of array with arguments type of comp function?



Of course I can replace the type of the argument array by any in the implementation signature, it works, but I would like to know if there is a better way to handle this case.










share|improve this question























  • What if you change T to ArrayLike<T>? Since you also allow a Float32Array you will not be using any of the Array prototype function. If you also use it in a for-of loop or something you may add ArrayLike<T> & Iterable<T>.

    – Tim Lundqvist
    Nov 14 '18 at 14:28











  • Thanks, I didn't know about these types in Typescript. Iterable<T> seems to work (and therefore, no overload is required). I can't use ArrayLike which seems to be readonly (the array is mutaded in the implementation).

    – SpacePotatoes
    Nov 14 '18 at 14:46
















0















I have a recursive function with 2 overloads :



export function select(
array: Float32Array,
first: number,
nth: number,
last: number,
comp: (a: number, b: number) => boolean,
): void;
export function select<T>(
array: T,
first: number,
nth: number,
last: number,
comp: (a: T, b: T) => boolean,
): void;
export function select<T>(
array: Float32Array | T,
first: number,
nth: number,
last: number,
comp: (a: number | T, b: number | T) => boolean,
): void {
// Implementation of Floyd-Rivest algorithm
// Some code
select(array, newFirst, nth, newLast, comp);
// Some code
}


Typescript complains about variable array when calling select function recursively in the implementation :




The argument of type 'Float32Array | T' is not assignable to the parameter of type '(number | T)'.




First, I don't really understand why typescript try to compare the type of argument array with a type (number | T) which does not exist in the different signatures. Does it try to compare the type of array with arguments type of comp function?



Of course I can replace the type of the argument array by any in the implementation signature, it works, but I would like to know if there is a better way to handle this case.










share|improve this question























  • What if you change T to ArrayLike<T>? Since you also allow a Float32Array you will not be using any of the Array prototype function. If you also use it in a for-of loop or something you may add ArrayLike<T> & Iterable<T>.

    – Tim Lundqvist
    Nov 14 '18 at 14:28











  • Thanks, I didn't know about these types in Typescript. Iterable<T> seems to work (and therefore, no overload is required). I can't use ArrayLike which seems to be readonly (the array is mutaded in the implementation).

    – SpacePotatoes
    Nov 14 '18 at 14:46














0












0








0


0






I have a recursive function with 2 overloads :



export function select(
array: Float32Array,
first: number,
nth: number,
last: number,
comp: (a: number, b: number) => boolean,
): void;
export function select<T>(
array: T,
first: number,
nth: number,
last: number,
comp: (a: T, b: T) => boolean,
): void;
export function select<T>(
array: Float32Array | T,
first: number,
nth: number,
last: number,
comp: (a: number | T, b: number | T) => boolean,
): void {
// Implementation of Floyd-Rivest algorithm
// Some code
select(array, newFirst, nth, newLast, comp);
// Some code
}


Typescript complains about variable array when calling select function recursively in the implementation :




The argument of type 'Float32Array | T' is not assignable to the parameter of type '(number | T)'.




First, I don't really understand why typescript try to compare the type of argument array with a type (number | T) which does not exist in the different signatures. Does it try to compare the type of array with arguments type of comp function?



Of course I can replace the type of the argument array by any in the implementation signature, it works, but I would like to know if there is a better way to handle this case.










share|improve this question














I have a recursive function with 2 overloads :



export function select(
array: Float32Array,
first: number,
nth: number,
last: number,
comp: (a: number, b: number) => boolean,
): void;
export function select<T>(
array: T,
first: number,
nth: number,
last: number,
comp: (a: T, b: T) => boolean,
): void;
export function select<T>(
array: Float32Array | T,
first: number,
nth: number,
last: number,
comp: (a: number | T, b: number | T) => boolean,
): void {
// Implementation of Floyd-Rivest algorithm
// Some code
select(array, newFirst, nth, newLast, comp);
// Some code
}


Typescript complains about variable array when calling select function recursively in the implementation :




The argument of type 'Float32Array | T' is not assignable to the parameter of type '(number | T)'.




First, I don't really understand why typescript try to compare the type of argument array with a type (number | T) which does not exist in the different signatures. Does it try to compare the type of array with arguments type of comp function?



Of course I can replace the type of the argument array by any in the implementation signature, it works, but I would like to know if there is a better way to handle this case.







typescript generics recursion overloading






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 14 '18 at 14:19









SpacePotatoesSpacePotatoes

11




11













  • What if you change T to ArrayLike<T>? Since you also allow a Float32Array you will not be using any of the Array prototype function. If you also use it in a for-of loop or something you may add ArrayLike<T> & Iterable<T>.

    – Tim Lundqvist
    Nov 14 '18 at 14:28











  • Thanks, I didn't know about these types in Typescript. Iterable<T> seems to work (and therefore, no overload is required). I can't use ArrayLike which seems to be readonly (the array is mutaded in the implementation).

    – SpacePotatoes
    Nov 14 '18 at 14:46



















  • What if you change T to ArrayLike<T>? Since you also allow a Float32Array you will not be using any of the Array prototype function. If you also use it in a for-of loop or something you may add ArrayLike<T> & Iterable<T>.

    – Tim Lundqvist
    Nov 14 '18 at 14:28











  • Thanks, I didn't know about these types in Typescript. Iterable<T> seems to work (and therefore, no overload is required). I can't use ArrayLike which seems to be readonly (the array is mutaded in the implementation).

    – SpacePotatoes
    Nov 14 '18 at 14:46

















What if you change T to ArrayLike<T>? Since you also allow a Float32Array you will not be using any of the Array prototype function. If you also use it in a for-of loop or something you may add ArrayLike<T> & Iterable<T>.

– Tim Lundqvist
Nov 14 '18 at 14:28





What if you change T to ArrayLike<T>? Since you also allow a Float32Array you will not be using any of the Array prototype function. If you also use it in a for-of loop or something you may add ArrayLike<T> & Iterable<T>.

– Tim Lundqvist
Nov 14 '18 at 14:28













Thanks, I didn't know about these types in Typescript. Iterable<T> seems to work (and therefore, no overload is required). I can't use ArrayLike which seems to be readonly (the array is mutaded in the implementation).

– SpacePotatoes
Nov 14 '18 at 14:46





Thanks, I didn't know about these types in Typescript. Iterable<T> seems to work (and therefore, no overload is required). I can't use ArrayLike which seems to be readonly (the array is mutaded in the implementation).

– SpacePotatoes
Nov 14 '18 at 14:46












1 Answer
1






active

oldest

votes


















0














The problem is that the implementation overload (ie. the last one) is not directly callable, so when you call the function recursively the types have to be compatible with one of the two overloads, and the union is not compatible with either (typescript will not try to combine signatures to get to allow unions to be passed in)



The simplest solution in such a situation is to duplicate the implementation signature:



export function select(
array: Float32Array,
first: number,
nth: number,
last: number,
comp: (a: number, b: number) => boolean,
): void;
export function select<T>(
array: T,
first: number,
nth: number,
last: number,
comp: (a: T, b: T) => boolean,
): void;
export function select<T>(
array: Float32Array | T,
first: number,
nth: number,
last: number,
comp: (a: number | T, b: number | T) => boolean,
): void;
export function select<T>(
array: Float32Array | T,
first: number,
nth: number,
last: number,
comp: (a: number | T, b: number | T) => boolean,
): void {
// Implementation of Floyd-Rivest algorithm
// Some code
let newFirst = 0
let newLast = 0
select(array, newFirst, nth, newLast, comp);
// Some code
}


Another solution would be to use a type that is more general and is applicable for both types of array, as suggested in the comments.






share|improve this answer
























  • Doesn't adding a union signature basically defeat the purpose of the overloads?

    – Aaron
    Nov 14 '18 at 16:24











  • Not necessarily .. the first overload will be active for FloatArrays so the callback will take numbers. For other Ts the callback will take T. Only if it's a union of type FloatArray | T will the last overload be triggered

    – Titian Cernicova-Dragomir
    Nov 14 '18 at 16:33











  • But it seems like you can basically pass anything that satisfies the union and it'll compile, even though it could be an error... like select(floatArray, 1, 2, 3, (a: string, b: string) => a == b) is allowed because it floatArray matches Float32Array and (string, string) => boolean matches (T, T) => boolean... even though it no longer makes sense.

    – Aaron
    Nov 14 '18 at 16:40











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
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53302360%2foverloading-a-recursive-function-in-typescript-with-array-and-typedarray%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









0














The problem is that the implementation overload (ie. the last one) is not directly callable, so when you call the function recursively the types have to be compatible with one of the two overloads, and the union is not compatible with either (typescript will not try to combine signatures to get to allow unions to be passed in)



The simplest solution in such a situation is to duplicate the implementation signature:



export function select(
array: Float32Array,
first: number,
nth: number,
last: number,
comp: (a: number, b: number) => boolean,
): void;
export function select<T>(
array: T,
first: number,
nth: number,
last: number,
comp: (a: T, b: T) => boolean,
): void;
export function select<T>(
array: Float32Array | T,
first: number,
nth: number,
last: number,
comp: (a: number | T, b: number | T) => boolean,
): void;
export function select<T>(
array: Float32Array | T,
first: number,
nth: number,
last: number,
comp: (a: number | T, b: number | T) => boolean,
): void {
// Implementation of Floyd-Rivest algorithm
// Some code
let newFirst = 0
let newLast = 0
select(array, newFirst, nth, newLast, comp);
// Some code
}


Another solution would be to use a type that is more general and is applicable for both types of array, as suggested in the comments.






share|improve this answer
























  • Doesn't adding a union signature basically defeat the purpose of the overloads?

    – Aaron
    Nov 14 '18 at 16:24











  • Not necessarily .. the first overload will be active for FloatArrays so the callback will take numbers. For other Ts the callback will take T. Only if it's a union of type FloatArray | T will the last overload be triggered

    – Titian Cernicova-Dragomir
    Nov 14 '18 at 16:33











  • But it seems like you can basically pass anything that satisfies the union and it'll compile, even though it could be an error... like select(floatArray, 1, 2, 3, (a: string, b: string) => a == b) is allowed because it floatArray matches Float32Array and (string, string) => boolean matches (T, T) => boolean... even though it no longer makes sense.

    – Aaron
    Nov 14 '18 at 16:40
















0














The problem is that the implementation overload (ie. the last one) is not directly callable, so when you call the function recursively the types have to be compatible with one of the two overloads, and the union is not compatible with either (typescript will not try to combine signatures to get to allow unions to be passed in)



The simplest solution in such a situation is to duplicate the implementation signature:



export function select(
array: Float32Array,
first: number,
nth: number,
last: number,
comp: (a: number, b: number) => boolean,
): void;
export function select<T>(
array: T,
first: number,
nth: number,
last: number,
comp: (a: T, b: T) => boolean,
): void;
export function select<T>(
array: Float32Array | T,
first: number,
nth: number,
last: number,
comp: (a: number | T, b: number | T) => boolean,
): void;
export function select<T>(
array: Float32Array | T,
first: number,
nth: number,
last: number,
comp: (a: number | T, b: number | T) => boolean,
): void {
// Implementation of Floyd-Rivest algorithm
// Some code
let newFirst = 0
let newLast = 0
select(array, newFirst, nth, newLast, comp);
// Some code
}


Another solution would be to use a type that is more general and is applicable for both types of array, as suggested in the comments.






share|improve this answer
























  • Doesn't adding a union signature basically defeat the purpose of the overloads?

    – Aaron
    Nov 14 '18 at 16:24











  • Not necessarily .. the first overload will be active for FloatArrays so the callback will take numbers. For other Ts the callback will take T. Only if it's a union of type FloatArray | T will the last overload be triggered

    – Titian Cernicova-Dragomir
    Nov 14 '18 at 16:33











  • But it seems like you can basically pass anything that satisfies the union and it'll compile, even though it could be an error... like select(floatArray, 1, 2, 3, (a: string, b: string) => a == b) is allowed because it floatArray matches Float32Array and (string, string) => boolean matches (T, T) => boolean... even though it no longer makes sense.

    – Aaron
    Nov 14 '18 at 16:40














0












0








0







The problem is that the implementation overload (ie. the last one) is not directly callable, so when you call the function recursively the types have to be compatible with one of the two overloads, and the union is not compatible with either (typescript will not try to combine signatures to get to allow unions to be passed in)



The simplest solution in such a situation is to duplicate the implementation signature:



export function select(
array: Float32Array,
first: number,
nth: number,
last: number,
comp: (a: number, b: number) => boolean,
): void;
export function select<T>(
array: T,
first: number,
nth: number,
last: number,
comp: (a: T, b: T) => boolean,
): void;
export function select<T>(
array: Float32Array | T,
first: number,
nth: number,
last: number,
comp: (a: number | T, b: number | T) => boolean,
): void;
export function select<T>(
array: Float32Array | T,
first: number,
nth: number,
last: number,
comp: (a: number | T, b: number | T) => boolean,
): void {
// Implementation of Floyd-Rivest algorithm
// Some code
let newFirst = 0
let newLast = 0
select(array, newFirst, nth, newLast, comp);
// Some code
}


Another solution would be to use a type that is more general and is applicable for both types of array, as suggested in the comments.






share|improve this answer













The problem is that the implementation overload (ie. the last one) is not directly callable, so when you call the function recursively the types have to be compatible with one of the two overloads, and the union is not compatible with either (typescript will not try to combine signatures to get to allow unions to be passed in)



The simplest solution in such a situation is to duplicate the implementation signature:



export function select(
array: Float32Array,
first: number,
nth: number,
last: number,
comp: (a: number, b: number) => boolean,
): void;
export function select<T>(
array: T,
first: number,
nth: number,
last: number,
comp: (a: T, b: T) => boolean,
): void;
export function select<T>(
array: Float32Array | T,
first: number,
nth: number,
last: number,
comp: (a: number | T, b: number | T) => boolean,
): void;
export function select<T>(
array: Float32Array | T,
first: number,
nth: number,
last: number,
comp: (a: number | T, b: number | T) => boolean,
): void {
// Implementation of Floyd-Rivest algorithm
// Some code
let newFirst = 0
let newLast = 0
select(array, newFirst, nth, newLast, comp);
// Some code
}


Another solution would be to use a type that is more general and is applicable for both types of array, as suggested in the comments.







share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 14 '18 at 15:45









Titian Cernicova-DragomirTitian Cernicova-Dragomir

65.7k34361




65.7k34361













  • Doesn't adding a union signature basically defeat the purpose of the overloads?

    – Aaron
    Nov 14 '18 at 16:24











  • Not necessarily .. the first overload will be active for FloatArrays so the callback will take numbers. For other Ts the callback will take T. Only if it's a union of type FloatArray | T will the last overload be triggered

    – Titian Cernicova-Dragomir
    Nov 14 '18 at 16:33











  • But it seems like you can basically pass anything that satisfies the union and it'll compile, even though it could be an error... like select(floatArray, 1, 2, 3, (a: string, b: string) => a == b) is allowed because it floatArray matches Float32Array and (string, string) => boolean matches (T, T) => boolean... even though it no longer makes sense.

    – Aaron
    Nov 14 '18 at 16:40



















  • Doesn't adding a union signature basically defeat the purpose of the overloads?

    – Aaron
    Nov 14 '18 at 16:24











  • Not necessarily .. the first overload will be active for FloatArrays so the callback will take numbers. For other Ts the callback will take T. Only if it's a union of type FloatArray | T will the last overload be triggered

    – Titian Cernicova-Dragomir
    Nov 14 '18 at 16:33











  • But it seems like you can basically pass anything that satisfies the union and it'll compile, even though it could be an error... like select(floatArray, 1, 2, 3, (a: string, b: string) => a == b) is allowed because it floatArray matches Float32Array and (string, string) => boolean matches (T, T) => boolean... even though it no longer makes sense.

    – Aaron
    Nov 14 '18 at 16:40

















Doesn't adding a union signature basically defeat the purpose of the overloads?

– Aaron
Nov 14 '18 at 16:24





Doesn't adding a union signature basically defeat the purpose of the overloads?

– Aaron
Nov 14 '18 at 16:24













Not necessarily .. the first overload will be active for FloatArrays so the callback will take numbers. For other Ts the callback will take T. Only if it's a union of type FloatArray | T will the last overload be triggered

– Titian Cernicova-Dragomir
Nov 14 '18 at 16:33





Not necessarily .. the first overload will be active for FloatArrays so the callback will take numbers. For other Ts the callback will take T. Only if it's a union of type FloatArray | T will the last overload be triggered

– Titian Cernicova-Dragomir
Nov 14 '18 at 16:33













But it seems like you can basically pass anything that satisfies the union and it'll compile, even though it could be an error... like select(floatArray, 1, 2, 3, (a: string, b: string) => a == b) is allowed because it floatArray matches Float32Array and (string, string) => boolean matches (T, T) => boolean... even though it no longer makes sense.

– Aaron
Nov 14 '18 at 16:40





But it seems like you can basically pass anything that satisfies the union and it'll compile, even though it could be an error... like select(floatArray, 1, 2, 3, (a: string, b: string) => a == b) is allowed because it floatArray matches Float32Array and (string, string) => boolean matches (T, T) => boolean... even though it no longer makes sense.

– Aaron
Nov 14 '18 at 16:40




















draft saved

draft discarded




















































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.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53302360%2foverloading-a-recursive-function-in-typescript-with-array-and-typedarray%23new-answer', 'question_page');
}
);

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







Popular posts from this blog

Florida Star v. B. J. F.

Danny Elfman

Lugert, Oklahoma