給定一個型別:
type Book = {
__typename?: 'Book';
author?: {
__typename?: 'Author';
name?: string;
};
};
我想__typename遞回地從屬性中洗掉可選標志。導致:
type TypedBook = DeepMarkRequired<Book, "__typename">;
// type TypedBook = {
// __typename: 'Book';
// author?: {
// __typename: 'Author';
// name?: string;
// };
// };
ts-essentials有MarkRequired,但它不是遞回的,當我嘗試一個簡單的實作時:
type DeepMarkRequired<T extends object, K extends PropertyKey> = MarkRequired<
{ [P in keyof T]: T[P] extends object ? DeepMarkRequired<T[P], K> : T[P] },
K
>;
打字稿抱怨在第3行是K不滿足keyof T,這是有道理的,因為Required和Pick這兩個要求keyof T,而不是PropertyKey允許這是通用的。我不確定如何允許將任意引數名稱一直沿樹向下傳遞。
uj5u.com熱心網友回復:
你可以用組合構建這個你自己Pick,Required和Omit實用的型別,但是你錯過一塊是你需要做的是這樣Pick<T, Extract<keyof T, K>>用的Extract<T, U>實用型,如果你不知道是否K是一個關鍵T與否。
但我更喜歡使用密鑰重新映射來撰寫這個,比如:
type DeepMarkRequired<T, K extends PropertyKey> = (
{ [P in keyof T as Extract<P, K>]-?: DeepMarkRequired<T[P], K> } &
{ [P in keyof T as Exclude<P, K>]: DeepMarkRequired<T[P], K> }
)
這產生
type TypedBook = DeepMarkRequired<Book, "__typename">;
/* type TypedBook = {
__typename: "Book";
} & {
author?: DeepMarkRequired<{
__typename?: "Author" | undefined;
name?: string | undefined;
} | undefined, "__typename">;
} */
這是你想要的型別。如果您希望它看起來更像您的版本,您可以強制編譯器通過條件型別推斷將型別復制到新型別引數來兌現所有這些別名,然后對其進行身份映射:
type DeepMarkRequired<T, K extends PropertyKey> = (
{ [P in keyof T as Extract<P, K>]-?: DeepMarkRequired<T[P], K> } &
{ [P in keyof T as Exclude<P, K>]: DeepMarkRequired<T[P], K> }
) extends infer O ? { [P in keyof O]: O[P] } : never
產生
/* type TypedBook = {
__typename: "Book";
author?: {
__typename: "Author";
name?: string | undefined;
} | undefined;
} */
Playground 代碼鏈接
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/405752.html
標籤:
上一篇:運算子“ ”不能應用于型別“字串”是否有解決方法?數字'和'字串'|數字'
下一篇:MOBX和React集成
