Typescript -在对象的键上循环时类型缩小



当我必须迭代mappedTypes的键时,我总是努力使Typescript缩小与我迭代的键相关的值的类型,并始终以ts-ignore结束…

一个代码示例说明了这个问题值1000个字:)在这里!

type Person = {
firstName?: string
lastName?: string
age?: number
}
type Update<T> = {
before: T,
after: T,
}
type Updates = { [Key in keyof Person]: Update<Person[Key]> }
/**
* Dummy transformers for illustration purposes
*/
const transformers : {[Key in keyof Person]: (value: Person[Key]) => Person[Key]} = {
firstName: value => value?.toUpperCase(),
lastName: value => value?.toUpperCase(),
age: value => typeof value === 'undefined'? 0 : value + 2
}
/**
* Input: {firstName: 'david', age: 23}
* Output: {firstName: {before: 'david', after: 'David'}, age: {before: 22, after: 24}}
* @param person
*/
function enrichPerson (person: Person): Updates {
return Object.keys(person).reduce(
(previousUpdates, key) => {
const typedKey = key as keyof Person
const result = { ...previousUpdates }
result[typedKey] = {
before: person[typedKey],                           // <--- Typing problem Here
after: transformers[typedKey](person[typedKey]),    // <--- Typing problem Here
}
return result
},
{} as Updates
)
}
export {}

我能做些什么来缩小值的类型?如果不可能,在这种情况下你会使用什么模式?

谢谢你的帮助!这个问题困扰我!

我增加了一个类型Updatetable<Type>和另一个函数update,使赋值类型安全。我希望这对你有用:

type Person = {
firstName?: string;
lastName?: string;
age?: number;
};
type Update<T> = {
before: T;
after: T;
};
type Updatetable<Type> = { [Key in keyof Type]: Update<Type[Key]> };
type Updates = Updatetable<Person>;
/**
* Dummy transformers for illustration purposes
*/
const transformers: { [Key in keyof Person]: (value?: Person[Key]) => Person[Key] } = {
firstName: (value) => value?.toUpperCase(),
lastName: (value) => value?.toUpperCase(),
age: (value) => (typeof value === "undefined" ? 0 : value + 2),
};
/**
* Input: {firstName: 'david', age: 23}
* Output: {firstName: {before: 'david', after: 'David'}, age: {before: 22, after: 24}}
* @param person
*/
function enrichPerson(person: Person): Updates {
return Object.keys(person).reduce<Updates>((previousUpdates, key) => {
const typedKey = key as keyof Person;
const result: Updates = { ...previousUpdates };
update(result, typedKey, { before: person[typedKey], after: person[typedKey] });
return result;
}, {});
}
function update<Type, Key extends keyof Type>(result: Updatetable<Type>, key: Key, value: Update<Type[Key]>): void {
result[key] = value;
}
export {};
感谢@okan aslan为我指明了正确的方向。再次感谢!下面是解决这个问题的代码示例的修改版本。

查看两个辅助函数updateapplyTransformer的介绍。

type Person = {
firstName?: string;
lastName?: string;
age?: number;
};
type Update<T> = {
before: T;
after: T;
};
type Updatetable<Type> = { [Key in keyof Type]: Update<Type[Key]> };
type Updates = Updatetable<Person>;
type Transformer<Type, Key extends keyof Required<Type>> = (x: Type[Key]) => Type[Key]
type Transformers<Type> = { [Key in keyof Required<Type>]: Transformer<Type, Key> }

function update<T, K extends keyof T> (obj: Updatetable<T>, key: K, newValue: Update<T[K]>): void {
obj[key] = newValue
}
function applyTransformer<T, K extends keyof Required<T>> (
transformers: Transformers<T>,
key: K,
input: T[K]
): T[K] {
return transformers[key](input)
}

/**
* Dummy transformers for illustration purposes
*/
const transformers: { [Key in keyof Required<Person>]: (value?: Person[Key]) => Person[Key] } = {
firstName: (value) => value?.toUpperCase(),
lastName: (value) => value?.toUpperCase(),
age: (value) => (typeof value === 'undefined' ? 0 : value + 2),
}
/**
* Input: {firstName: 'david', age: 22}
* Output: {firstName: {before: 'david', after: 'David'}, age: {before: 22, after: 24}}
* @param person
*/
function enrichPerson (person: Person): Updates {
return Object.keys(person).reduce<Updates>((previousUpdates, key) => {
const typedKey = key as keyof Person
const result: Updates = { ...previousUpdates }
update(result, typedKey, {
before: person[typedKey],
after:  applyTransformer(transformers, typedKey, person[typedKey])
})
return result
}, {})
}
export {}