键入将对象中的 属性 映射到另一个 属性 的函数
Typing a function that maps a property in an object to another property
我正在尝试键入一个将对象中的 属性 映射到另一个 属性 的函数。
例如mapProperty
函数可以用作 mapProperty('_id', 'id', { _id: "arst" } )
。结果类型应该是 { id: string }
.
我创建了下面输入的函数 mapProperty
,但我觉得 as unknown as M
不是必需的。但是,当我不使用它时,出现以下错误:
Type 'T & { [x: string]: T[K]; }'
is not assignable to type 'M'
.
'M'
could be instantiated with an arbitrary type which could be unrelated to 'T & { [x: string]: T[K]; }'
.
也无法将 return 值键入 : { [key: L]: T[K] }
。
有什么解决方案?
const mapProperty = <T, K extends keyof T, M, L extends keyof M>(
from: K,
to: L,
obj: T,
): M => {
const prop = obj[from];
delete obj[from];
return ({ ...obj, [to]: prop } as unknown) as M;
};
编辑:(我使用了 Николай Γольцев 的答案,但稍作改动)
我添加了一个参数,它是一个映射映射值的函数 属性:
const mapProperty = <T, K extends keyof T, L extends string, M = T[K]>(
obj: T,
from: K,
to: L,
fn?: (x: T[K]) => M,
): Omit<T, K> & { [key in L]: M } => {
const prop = fn ? fn(obj[from]) : obj[from];
delete obj[from];
return { ...obj, [to]: prop } as any;
};
可以这样写:
const mapProperty = <T, K extends keyof T, L extends string>(
from: K,
to: L,
obj: T,
): Omit<T, K> & {
[key in L]: T[K]
} => {
const prop = obj[from];
delete obj[from];
return { ...obj, [to]: prop } as any;
};
const k = mapProperty('_id', 'id', { _id: "arst", k: true } )
return 语句中出现错误,因为 delete
运算符对变量类型不做任何操作。删除操作后仍然是T
。计算 属性,据我所知,总是给出类型 { [x: string]: T }
.
请看下一个解决方案:
type Data = { age: 1, name: 'string' }
// Main utility
type Replace<O, P1 extends keyof O, P2 extends string> =
Pick<O, Exclude<keyof O, P1>>
& { [P in P2]: O[P1] }
type Result = Replace<Data, 'name', 'surname'>
const mapProperty = <O, P1 extends keyof O, P2 extends string>(obj: O, from: P1, to: P2): Replace<O, P1, P2> => {
const { [from]: replaced, ...rest } = obj;
// don't know how to get rid of casting operators
return {
...rest,
[to]: replaced
} as unknown as Replace<O, P1, P2>
}
const data: Data = { age: 1, name: 'string' }
const result = mapProperty(data, 'age', 'year')
type Res = keyof typeof result // "year" | "name"
根本不使用 delete
运算符被认为是一个好习惯,因为它很慢并且还有其他缺点。作为替代方案,您可以改用 Reflect.deleteProperty()。由于计算的性质,我不知道如何摆脱 unknown
转换 [to]。
我正在尝试键入一个将对象中的 属性 映射到另一个 属性 的函数。
例如mapProperty
函数可以用作 mapProperty('_id', 'id', { _id: "arst" } )
。结果类型应该是 { id: string }
.
我创建了下面输入的函数 mapProperty
,但我觉得 as unknown as M
不是必需的。但是,当我不使用它时,出现以下错误:
Type
'T & { [x: string]: T[K]; }'
is not assignable to type'M'
.
'M'
could be instantiated with an arbitrary type which could be unrelated to'T & { [x: string]: T[K]; }'
.
也无法将 return 值键入 : { [key: L]: T[K] }
。
有什么解决方案?
const mapProperty = <T, K extends keyof T, M, L extends keyof M>(
from: K,
to: L,
obj: T,
): M => {
const prop = obj[from];
delete obj[from];
return ({ ...obj, [to]: prop } as unknown) as M;
};
编辑:(我使用了 Николай Γольцев 的答案,但稍作改动)
我添加了一个参数,它是一个映射映射值的函数 属性:
const mapProperty = <T, K extends keyof T, L extends string, M = T[K]>(
obj: T,
from: K,
to: L,
fn?: (x: T[K]) => M,
): Omit<T, K> & { [key in L]: M } => {
const prop = fn ? fn(obj[from]) : obj[from];
delete obj[from];
return { ...obj, [to]: prop } as any;
};
可以这样写:
const mapProperty = <T, K extends keyof T, L extends string>(
from: K,
to: L,
obj: T,
): Omit<T, K> & {
[key in L]: T[K]
} => {
const prop = obj[from];
delete obj[from];
return { ...obj, [to]: prop } as any;
};
const k = mapProperty('_id', 'id', { _id: "arst", k: true } )
return 语句中出现错误,因为 delete
运算符对变量类型不做任何操作。删除操作后仍然是T
。计算 属性,据我所知,总是给出类型 { [x: string]: T }
.
请看下一个解决方案:
type Data = { age: 1, name: 'string' }
// Main utility
type Replace<O, P1 extends keyof O, P2 extends string> =
Pick<O, Exclude<keyof O, P1>>
& { [P in P2]: O[P1] }
type Result = Replace<Data, 'name', 'surname'>
const mapProperty = <O, P1 extends keyof O, P2 extends string>(obj: O, from: P1, to: P2): Replace<O, P1, P2> => {
const { [from]: replaced, ...rest } = obj;
// don't know how to get rid of casting operators
return {
...rest,
[to]: replaced
} as unknown as Replace<O, P1, P2>
}
const data: Data = { age: 1, name: 'string' }
const result = mapProperty(data, 'age', 'year')
type Res = keyof typeof result // "year" | "name"
根本不使用 delete
运算符被认为是一个好习惯,因为它很慢并且还有其他缺点。作为替代方案,您可以改用 Reflect.deleteProperty()。由于计算的性质,我不知道如何摆脱 unknown
转换 [to]。