2
votes

How do I fix below code to solve 2349?

function fillArray<T>(arr: T[], value: T | ((index: number) => T)): void {
    if (typeof value === 'function') {
        for (let i = 0; i < arr.length; i++) {
            arr[i] = value(i)
        }
    } else {
        arr.fill(value)
    }
}

TypeScript report error for value(i) as:

This expression is not callable. Not all constituents of type '((index: number) => T) | (T & Function)' are callable.

See: Playground Link

1

1 Answers

2
votes

Not sure what exactly causes the error (might be related to this issue with narrowing generic type parameters).

As a workaround, you can define and use custom type guard:

function isFunction<T>(value: T | ((index: number) => T)): value is (index: number) => T {
    return typeof value === 'function';
}
    
function fillArray<T>(arr: T[], value: T | ((index: number) => T)): void {
    if (isFunction(value)) {
        for (let i = 0; i < arr.length; i++) {
            arr[i] = value(i)
        }
    } else {
        arr.fill(value)
    }
}

Playground


Other working option discovered by @VLAZ is using instanceof guard instead of typeof:

function fillArray<T>(arr: T[], value: T | ((index: number) => T)): void {
    if (value instanceof Function) {
        for (let i = 0; i < arr.length; i++) {
            arr[i] = value(i)
        }
    } else {
        arr.fill(value)
    }
}

Playground


One more working option - make the array type a generic parameter:

function fillArray<A extends Array<unknown>>(
    arr: A,
    value: A[number] | ((index: number) => A[number])
): void {
    if (typeof value === 'function') {
        for (let i = 0; i < arr.length; i++) {
            arr[i] = value(i)
        }
    } else {
        arr.fill(value)
    }
}

Playground