【问题标题】:Type safe way to append field by name键入按名称附加字段的安全方式
【发布时间】:2019-11-28 06:40:42
【问题描述】:

尝试实现函数,接收对象O,字段名称N和字段值T返回对象,该对象具有来自O的所有字段,名称为N的字段类型为T

试图实现这样的方式:

export function immutableAdd<O, N extends string, T>(object: O, name: N, value: T): O & { [key: N]: T } {
    return { ...object, [name]: value };
}

let a = { a: 3 };
let b = immutableAdd(a, 'test', 'value');
// `b` should have type { a: number, test: string } here
let c = b.test;
c === 'value'

但是这段代码不起作用,因为这部分有错误:{ [key: N]: T }(索引签名参数类型必须是'string'或'number')

这个函数的返回类型怎么写?

【问题讨论】:

    标签: typescript typescript-generics


    【解决方案1】:

    我认为,您在这里有两个选择:a)为immutableAdd 返回类型添加类型断言或b)使用Record 类型。如果您可以稍微更改函数签名,我更喜欢 b),因为它更简洁/强制执行更强的输入。

    a) Type assertion

    export function immutableAdd<O, N extends string, T>(
        object: O, name: N, value: T): O & { [key in N]: T } {
        // or create separate const to assert the added property type only; like:
        // const prop = { [name]: value } as { [key in N]: T }    
        return { ...object, [name]: value } as O & { [key in N]: T }
    }
    
    let b = immutableAdd({ a: 3 }, 'test', 'value'); // {a: number; } & { test: string; }
    

    注意:我使用 mapped type { [key in N]: T } 作为返回类型的一部分以包含 name 属性。 { [key: N]: T }(您使用的)表示index signature,它只能有stringnumber 类型。在您的情况下,N 是具有约束extends string 的类型参数,而不是string,因此会出现编译器错误。

    return { ...object, [name]: value } 将解析为O &amp; { [x: string]: T; } 类型,因为name 的确切字符串文字类型未知(我们只知道它扩展了string),因此不能分配给O &amp; { [key in N]: T },所以我们投了。

    b) Record 类型

    export function immutableAdd<O, N extends string, T>(
        object: O, property: Record<N,T>): O & { [key in N]: T } {
        return { ...object, ...property };
    }
    
    let b = immutableAdd( { a: 3 }, { test: 'value' }); // { a: number; } & { test: string; }
    

    【讨论】:

      【解决方案2】:

      建议的返回类型是这样的:

      O & {[key : string] : T}
      

      或者这个:

      O & {[key : number] : T}
      

      字段名称的类型好像只能是字符串或数字

      【讨论】:

      • { [key in N]: T } 没问题。
      猜你喜欢
      • 1970-01-01
      • 2016-02-28
      • 2017-07-27
      • 2011-02-05
      • 1970-01-01
      • 2019-01-11
      • 2017-07-13
      • 1970-01-01
      相关资源
      最近更新 更多