題目
中文
實現一個ReplaceKeys
類型, 這個類型可以替換聯合類型中指定屬性的類型, 如果聯合類型中的某個類型沒有這個屬性, 那就跳過; ReplaceKeys
接受 3 個泛型參數.
例如:
type NodeA = {
type: 'A';
name: string;
flag: number;
};
type NodeB = {
type: 'B';
id: number;
flag: number;
};
type NodeC = {
type: 'C';
name: string;
flag: number;
};
type Nodes = NodeA | NodeB | NodeC;
type ReplacedNodes = ReplaceKeys<
Nodes,
'name' | 'flag',
{ name: number; flag: string }
>; // {type: 'A', name: number, flag: string} | {type: 'B', id: number, flag: string} | {type: 'C', name: number, flag: string} // would replace name from string to number, replace flag from number to string.
type ReplacedNotExistKeys = ReplaceKeys<Nodes, 'name', { aa: number }>; // {type: 'A', name: never, flag: number} | NodeB | {type: 'C', name: never, flag: number} // would replace name to never
English
Implement a type ReplaceKeys, that replace keys in union types, if some type has not this key, just skip replacing,
A type takes three arguments.
For example:
type NodeA = {
type: 'A';
name: string;
flag: number;
};
type NodeB = {
type: 'B';
id: number;
flag: number;
};
type NodeC = {
type: 'C';
name: string;
flag: number;
};
type Nodes = NodeA | NodeB | NodeC;
type ReplacedNodes = ReplaceKeys<
Nodes,
'name' | 'flag',
{ name: number; flag: string }
>; // {type: 'A', name: number, flag: string} | {type: 'B', id: number, flag: string} | {type: 'C', name: number, flag: string} // would replace name from string to number, replace flag from number to string.
type ReplacedNotExistKeys = ReplaceKeys<Nodes, 'name', { aa: number }>; // {type: 'A', name: never, flag: number} | NodeB | {type: 'C', name: never, flag: number} // would replace name to never
答案
type ReplaceKeys<
U extends object,
T extends string,
Y extends object
> = U extends U
? {
[P in keyof U]: P extends T
? P extends keyof Y
? Y[P]
: never
: U[P];
}
: never;