简体   繁体   中英

Why does TypeScript mark the type of argument from function as 'never'

Here is the union type of two signatures for the filter function and the function itself.

type Filter = {
  (arr: string[], f: (item: string) => boolean): string[]
  (arr: number[], f: (item: number) => boolean): number[]
}

let filter: Filter = (arr, func) => {
    let result = []
    for (let i in arr) {
        let item = arr[i]
        if (func(item)) {
            result.push(item)
        }
    }
    return result
}

The compiler accepts this argument as a function of the union type:

在此处输入图像描述

However, inside the function it doesn't and marks the argument item as never

在此处输入图像描述

The problem is that if a function is typed as ((item: string) => boolean) | ((item: number) => boolean) ((item: string) => boolean) | ((item: number) => boolean) there is nothing we can call this function that would be safe for either function signature ex:

let fn: ((item: string) => boolean) | ((item: number) => boolean)
fn = Math.random() > 0.5 ? (i: string) => !!i.toUpperCase() : (i: number)=> !!i.toExponential()

fn(10) // Will fail if the function is the one that accepts strings
fn("") // Will fail if the function is the one that accepts numbers

Playground Link

This is why for a union of functions typescript will infer an intersection for parameters. For primitive types this will always reduce to never , but it is more useful for object types where we can create objects that satisfy the intersection of two other object types.

TS does the best it can to infer the types of the parameters, but in this case the inferred parameters while correct are not very useful.

The better solution would be to use an explicit generic signature in this case:

type Filter = {
  (arr: string[], f: (item: string) => boolean): string[]
  (arr: number[], f: (item: number) => boolean): number[]
}

let filter: Filter = <T extends string | number>(arr: T[], func: (item: T) => boolean): T[] => {
    let result: T[] = []
    for (let i in arr) {
        let item = arr[i]
        if (func(item)) {
            result.push(item)
        }
    }
    return result;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM