繁体   English   中英

如何将 Typescript 函数重载与具有多个参数的函数一起使用?

[英]How to use Typescript Function Overloading with a function that has multiple parameters?

我有一个函数试图在数字数组中找到一个值。 该值可以是一个对象或一个数字。 如果值是一个对象,则有一个“key”属性用于从对象中获取数字值。

我正在尝试使用Function Overloading来拥有一个可以处理这两种情况的函数。

type ObjectType = {
    [key: string]: number
}

type FunctionType = {
    <T extends ObjectType>(v: T, list: number[], key: string): T | undefined
    (v: number, list: number[]): number | undefined
}

const find: FunctionType = <T extends ObjectType | number,>(v: T, list: number[], key?: string)=>{

    const value = typeof v === 'number' ? v : v[key]

    return list.find((item)=>{
        return item === value
    })
}

这会产生错误Type undefined cannot be used as an index type

但是在这个分支中,v的值是一个对象,那么key怎么没有定义呢?

TS-游乐场

谢谢

编辑

Alex Wayne 提出了一个解决方案,但它没有正确地将值缩小到一个数字。

如果我们不调用 list.find,而是调用一个只接受数字的自定义函数,typescript 会抛出错误


const findNumber = (v: number, list: number[])=>{
    /* Do stuff with v as a number */
    return list.indexOf(v)
}

const find: FunctionType = <T extends ObjectType | number>(v: T, list: number[], key?: keyof T)=>{
    const value = (key && typeof v === 'object') ? v[key] : v

    return list[findNumber(value, list)]
}

“ObjectType”类型不能分配给“number”类型

TS-游乐场

实现函数不知道它的重载是什么。 这意味着如果重载函数签名被删除,重载函数实现必须仍然完全有效。

因此,虽然如果typeof v === 'number'然后typeof key === 'string'编译器不知道这一点是正确的。

如果你纯粹看这个函数签名:

<T extends ObjectType | number,>(v: T, list: number[], key?: string)=>{

然后你会看到find({ someKey: 1 }, [1,2,3])是一个有效的调用。 重载阻止了该调用,但该函数在没有这些重载的情况下也必须有效。


这意味着要解决此问题,您必须在使用之前测试key是否存在。

const value = (key && typeof v === 'number') ? v : v[key]

然而,这又带来了一个新问题:

Type 'undefined' cannot be used as an index type.(2538)

我相信这是因为typeof v === 'number'不够细化。 我不确定它认为它可能是什么,但如果你反转三元并通过typeof v === 'object'打字稿进行优化,那么它会很高兴。

const value = (key && typeof v === 'object') ? v[key] : v

操场


最后,您可以在这里使用key: keyof T来提高类型安全性。

const find: FunctionType = <T extends ObjectType | number>(v: T, list: number[], key?: keyof T)=>{
    const value = (key && typeof v === 'object') ? v[key] : v

    return list.find((item)=>{
        return item === value
    })
}

看游乐场

首先,让我们确保无效状态是不可表示的。 让我们定义联合类型:

type IsObj<T> = {
    value: T, key: keyof T
}

type IsNumber = { value: number }

type Params<T> = IsObj<T> | IsNumber

您可能已经注意到,我绑定了第二个和第三个参数。

现在,我们可以定义我们的自定义类型保护:

const isNumber = <T,>(params: Params<T>): params is IsNumber => typeof params.value === 'number'

让我们把它放在一起:


type ObjectType = {
    [key: string]: number
}

type IsObj<T> = {
    value: T, key: keyof T
}

type IsNumber = { value: number }

type Params<T> = IsObj<T> | IsNumber

const isNumber = <T,>(params: Params<T>): params is IsNumber => typeof params.value === 'number'

type FunctionType = {
    <T extends ObjectType>(list: number[], params: IsObj<T>): T | undefined
    (list: number[], params: IsNumber): number | undefined
}

const find: FunctionType = <T extends ObjectType | number,>(list: number[], params: Params<T>) => {

    const value = isNumber(params) ? params.value : params.value[params.key]

    return list.find((item) => item === value)
}

const result = find([1, 2, 3], { value: 42}) // ok
const result_ = find([1, 2, 3], { value: { age: 2 }, key: 'age' }) // ok

const result__ = find([1, 2, 3], { value: { age: 2 }, key: 'name' }) // expected error
const result___ = find([1, 2, 3], { value: 42, key: 'name' }) // expected error

操场

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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