【问题标题】:Extending a return object with keys matching a dynamic child使用与动态子项匹配的键扩展返回对象
【发布时间】:2018-11-09 19:44:14
【问题描述】:

我想要一个函数,它接受一个带有可选键 (inst) 的对象,然后使用 inst 对象的键创建一个返回对象 - 例如:

function init( db, config ) {
    let ret = {};

    if ( config.inst ) {
        for (let [key, value] of Object.entries(config.inst)) {
            ret[ key ] = value+1; // would normally do some kind of processing here
        }
    }

    return ret;
}

如果使用init( db, { inst: { a: 1, b: 2 } } ); 调用它,它将返回{ a: 2, b: 3 }。是的,它有点多余,但我可以尽可能简化我的想法!

虽然用 Javascript 编写代码很容易,但我终其一生都想不出一个接口,我应该为这个函数定义一个接口,让 TypeScript 处理返回的数据和类型。

让我感到困惑的关键是如何获取inst 嵌套对象的键。我知道我可以使用keyofin 获取对象的键,但我看不到如何在此处应用它。

非常欢迎任何帮助!

跟进 - 更改返回属性的类型

作为后续,此答案假定返回参数的类型将与为inst 传入的类型相匹配。如果类型改变了怎么办?例如将数字更改为字符串,反之亦然?

type Config<T extends {}> = {
    inst?: T
}

function init<T extends {}>(db, config: Config<T>): T & {} {
    let ret: any = {};

    if ( config.inst ) {
        for (let [key, value] of Object.entries(config.inst)) {
            if ( typeof value === 'number' ) {
                ret[ key ] = value.toString();
            }
            else {
                ret[ key ] = parseInt( value, 10 );
            }
        }
    }

    return ret;
}


let { num, str } = init( null, { inst: { num: '1', str: 2 } } );

这样,被破坏的num 将是一个字符串,而str 将是一个数字,根据函数所做的“处理”,这是不正确的。有没有办法让 TypeScript 推断出正确的类型?

【问题讨论】:

    标签: typescript types


    【解决方案1】:

    如果我理解正确的话,这样的事情应该代表你在做什么,所以你实际上不需要对键做任何事情来正确传播类型信息:

    type Config<T extends {}> = {
        inst?: T
    }
    
    function init<T extends {}>(db, config: Config<T>): T | {} {
        let ret = {};
    
        if ( config.inst ) {
            for (let [key, value] of Object.entries(config.inst)) {
                ret[ key ] = value+1; // would normally do some kind of processing here
            }
        }
    
        return ret;
    }
    

    您可能应该为 false 情况返回空对象(例如未定义)以外的其他内容,以便事后以 TypeScript 理解的方式检查哪些情况发生了。

    【讨论】:

    • 太棒了谢谢。看来我完全是在叫错树了。我必须做一个小改动——返回类型是交集而不是联合。我已经编辑了我的原始帖子以添加一个后续问题,如果可以,我想知道当“处理”更改要返回的数据类型时该怎么办。
    【解决方案2】:

    如果您需要更改成员的类型,则需要将一些映射和条件类型添加到您的返回类型(有关它们的文档,请参阅 here)。您将需要根据条件类型来表达您执行的处理(实际上是根据类型复制处理算法),但至少调用者将获得适当的类型:

    type Config<T extends {}> = {
        inst?: T
    }
    
    function init<T extends {}>(db, config: Config<T>): {
      [P in keyof T]: // take each property of T
        T[P] extends number ? string : number // If the property T[P] is a number the new property type will be string otherwise it will be number
    } {
        let ret: any = {};
    
        if ( config.inst ) {
            for (let [key, value] of Object.entries(config.inst)) {
                if ( typeof value === 'number' ) {
                    ret[ key ] = value.toString();
                }
                else {
                    ret[ key ] = parseInt( value, 10 );
                }
            }
        }
    
        return ret;
    }
    
    
    let { num, str } = init( null, { inst: { num: '1', str: 2 } } );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-06-30
      • 2011-10-12
      • 1970-01-01
      • 2013-03-05
      • 1970-01-01
      • 2015-01-10
      • 1970-01-01
      相关资源
      最近更新 更多