type-fest
type-fest copied to clipboard
ArraySlice not working for optional elements
Bug description
For the use case described in https://github.com/sindresorhus/type-fest/issues/751 --- I'm attempting to use ArraySlice to get a list of trailing function parameters. But, if there's an optional parameter, it doesn't work. The optional parameter is stripped from the tuple.
import type { ArraySlice, ArrayTail } from 'type-fest';
function fn (a: number, b: string, c?: boolean) {}
type params = Parameters<typeof fn>;
//> [a: number, b: string, c?: boolean | undefined]
type tailParams = ArraySlice<params, 1>;
//> [string]
// should be [b: string, c?: boolean | undefined]
// ArrayTail does it correctly:
type tailParams2 = ArrayTail<params>;
//> [b: string, c?: boolean | undefined]
Repro
https://www.typescriptlang.org/play/?#code/JYWwDg9gTgLgBDAnmApnA3nAglKBDRAZQBtgBjFAGm1wIBU9hi4BfOAMyghDgHIlUAWnYoAzjF4BuAFCz2AVwB2ZGMAiKOGgBR4AXHEXyQAIxRRqx-eKjBFAc2pkA-PuMQIxFHkUBKDC1kBNDA8fBBROABeOAAFULwQFBgzUQAeIIh2TQA+GQB6POy4AG09AyNTczhLOGtbBzhnV3dPbzgAHzglABMUdlsUboBdQOQ0GEZiOLCI6Jx8IlIKVJCZ6gBGXOkCouK6+xGC2oALCHlibuq0Ypr9hqbqlq8NTp6+geHZbbyaBYYmODdCBiODAeBkaBQFAqYiIXTSIIISbTBKiABMUV+9EmK3i4S2OxKtxgNnsjhcjw8zw6XUUvX6ikGQyAA
I’m not sure if this is a good solution, but changing Array_['length'] to Required<Array_>['length'] seems to be the most cost-effective way to prevent the array’s length from becoming a union type when optional elements are present.
@naremloa The ArraySlice type need a rewrite, it has a lot of repeated syntax, use old or unnecessary types to do simple tasks.
Also can use UnknownArray instead of readonly unknown[]
@sindresorhus can I take this issue ?
Sure
@benzaria This type has quite a few interesting edge cases, so before diving into a refactor, I’d suggest we first go over the test cases properly.
Also, I have a somewhat working version in my stash, I'll see if I can clean it up and open a PR, maybe you can improve upon that.
There are also a couple of tests that are wrong in the existing test suite. For example, ArraySlice<[1, 2, 3, ...string[]], 1, 5> is expected to return [2, 3, string, string], but that's inaccurate. Because [1, 2, 3] satisfies [1, 2, 3, ...string[]], but [1, 2, 3].slice(1, 5) (i.e. [2, 3]) does not satisfy [2, 3, string, string]. The correct result here should be [2, 3, ...string[]].
@som-sm True, but I think the example u gave need a little change. I my opinion ArraySlice<[1, 2, 3, ...string[]], 1, 5> should return [2, 3, string?, string?] to satisfies both [2, 3] and [2, 3, 'foo']. because returning [2, 3, ...string[]] is wrong, and Users expect [2, 3, 'foo', 'bar', 'baz'] to throw and error. but in this case it wont.
because returning
[2, 3, ...string[]]is wrong
It's not wrong, it's just less precise.
Returning [2, 3, string?, string?] is also fine, it's just that the return value can get too long.
But this is just one example, there are many such edge cases that need proper handling.