输入按名称附加字段的安全方法
Type safe way to append field by name
正在尝试实现函数,该函数接收对象 O
、字段名称 N
和字段值 T
returns 对象,该对象具有来自 [=11= 的所有字段],以及名称为 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')
这个函数的return类型怎么写?
建议的 return 类型是这样的:
O & {[key : string] : T}
或者这个:
O & {[key : number] : T}
好像字段名称的类型只能是字符串或者数字
我认为,您在这里有两个选择:a) 为 immutableAdd
return 类型添加类型断言或 b) 使用 Record
类型。如果您可以稍微更改函数签名,我更喜欢 b),因为它更 concise/enforces 更强的打字。
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 }
as part of the return type to include the name
property. { [key: N]: T }
(what you used) indicates an index signature,它只能有string
或number
类型。在你的例子中,N
是一个带有约束 extends string
的类型参数,而不是 string
,因此是编译器错误。
return { ...object, [name]: value }
将解析为类型 O & { [x: string]: T; }
,因为 name
的确切字符串文字类型是未知的(我们只知道它扩展了 string
)并且因此不能分配给 O & { [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; }
正在尝试实现函数,该函数接收对象 O
、字段名称 N
和字段值 T
returns 对象,该对象具有来自 [=11= 的所有字段],以及名称为 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')
这个函数的return类型怎么写?
建议的 return 类型是这样的:
O & {[key : string] : T}
或者这个:
O & {[key : number] : T}
好像字段名称的类型只能是字符串或者数字
我认为,您在这里有两个选择:a) 为 immutableAdd
return 类型添加类型断言或 b) 使用 Record
类型。如果您可以稍微更改函数签名,我更喜欢 b),因为它更 concise/enforces 更强的打字。
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 }
as part of the return type to include the name
property. { [key: N]: T }
(what you used) indicates an index signature,它只能有string
或number
类型。在你的例子中,N
是一个带有约束 extends string
的类型参数,而不是 string
,因此是编译器错误。
return { ...object, [name]: value }
将解析为类型 O & { [x: string]: T; }
,因为 name
的确切字符串文字类型是未知的(我们只知道它扩展了 string
)并且因此不能分配给 O & { [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; }