【问题标题】:Typesript argument depends on another argument with a default valueTypescript 参数依赖于另一个具有默认值的参数
【发布时间】:2021-03-18 02:20:13
【问题描述】:

我正在尝试在 typescript 中创建一个函数,其中第二个可选参数是第一个参数的键。没有可选参数,我想要的函数看起来像

function getVal<T>(obj: T, key: keyof T) {
    return obj[key];
}

但是,我希望 key 是可选的,并采用默认值 "id"。但是,函数

function getValBad<T>(obj: T, key: keyof T = "id") {
    return obj[key];
}

不进行类型检查,因为 typescript 不知道 T 是否有 id 的键。这个问题的部分解决方法是写

function getValOk<T extends { id: any }>(obj: T, key: keyof T = "id") {
    return obj[key];
}

但是,这会强制 T 始终拥有 id 的密钥。

我的问题是,我可以编写一个函数getValGood 以便getValGood({id: 1}) 类型检查、getValGood({ID: 1}, "ID") 类型检查和getValGood({ID: 1}) 不进行类型检查。如果是这样,我如何在打字稿中表示getValGood

【问题讨论】:

    标签: typescript default-arguments keyof


    【解决方案1】:

    首先,您可能希望使用另一个通用参数来正确键入返回值。 (否则,obj[key] 将返回对象上所有可能值的联合,而不是只是key处的类型)

    您可以重载getVal 函数以获取一个对象和一个作为对象属性的键(2 个泛型),或者只使用一个泛型{ id: V } 并返回V 类型的东西:

    type GetVal = {
        <T, K extends keyof T>(obj: T, key: K): T[K];
        <V>(obj: { id: V }): V;
    };
    
    const getVal: GetVal = (obj: Record<string, unknown>, key = 'id') => {
        return obj[key];
    };
    
    const result1 = getVal({ foo: 'foo' }, 'foo');
    const result2 = getVal({ foo: 'foo' }, 'doesntexist'); // Fails
    
    const result3 = getVal({ id: 'val' });
    const result4 = getVal({ }); // Fails
    

    Demo

    【讨论】:

    • 是的,我认为重载和它在这里一样好。如果您致电getVal({id: "val", someOtherProp: 123}),您的版本可能会出现一些奇怪的多余属性问题,但这可以通过easily enough 解决。试图在没有重载的情况下做到这一点似乎是一场噩梦。
    【解决方案2】:

    我认为你应该为此使用函数重载:

    function getVal<V>(obj: {id: V}): V;
    function getVal<T, K extends keyof T>(obj: T, key: K): T[K];
    
    function getVal(obj: any, key = 'id') {
        return obj[key];
    }
    

    请注意,当函数具有重载签名时,Typescript 不会单独检查函数实现是否真正符合每个重载签名;根据重载签名确保您编写的实现是类型安全的,这取决于您。

    Typescript 至少仍会确保对函数的每次调用都是正确键入的。

    Playground Link

    【讨论】:

      猜你喜欢
      • 2017-03-09
      • 2013-11-18
      • 2023-01-24
      • 2020-11-13
      • 2022-11-14
      • 1970-01-01
      • 2019-08-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多