簡體   English   中英

如何防止`必需<T> ` 在打字稿中使用 --strictNullChecks 時從類型中刪除“未定義”

[英]How to prevent `Required<T>` in typescript from removing 'undefined' from the type when using --strictNullChecks

打字稿讓您免去“optionability” (?)-? 映射類型修飾符,可以很容易地與Required<T>類型一起使用。

type Required<T> = { [P in keyof T]-?: T[P] };

但是,在使用--strictNullChecks時注意以下幾點很重要(就像我一樣)。

請注意,在 --strictNullChecks 模式下,當同態映射類型刪除 ? 基礎類型中屬性的修飾符,它還從該屬性的類型中刪除 undefined:

我正在尋找一種方法來繞過這種副作用......

即我想刪除? 但如果|undefined存在我想保留它

為什么?

我有服務器生成的接口,這些接口具有可選 ( ? ) 屬性。 我想重構我的服務器代碼並添加/刪除成員。 因此,我想要一種方法,無論是否需要,我都必須為每個屬性顯式設置一個值(或顯式設置為undefined )。

困境:

  • 如果我使用Required<T>那么它會吞下我的| undefined | undefined| undefined是還有一個? 展示。

因此,具有諷刺意味的是以下內容:

export type RequiredDog = Required <{

    bark: 'loud' | 'quiet' | undefined,
    bite?: 'nip' | 'clamp' | undefined
}>; 

實際上變成了這樣:

type RequiredDog = {
    bark: "loud" | "quiet" | undefined;
    bite: "nip" | "clamp";
}

所以比bark更可選的bite現在實際上更少可選了!

有沒有辦法去掉? 不刪除undefined

如果我試圖實現一個不會從屬性中剝離undefinedRequired<> ,我可能會這樣做:

type RequiredKeepUndefined<T> = { [K in keyof T]-?: [T[K]] } extends infer U
  ? U extends Record<keyof U, [any]> ? { [K in keyof U]: U[K][0] } : never
  : never;

我在這里用一堆映射條件類型做的是將值類型包裝在一個單元組中,使其成為Required ,然后解開單元組。 這在精神上與您的答案相似,但如果有人在屬性中使用"undefined"作為字符串文字,則不會發生沖突。

您可以看到它的行為符合要求:

interface Dog {
    bark: "loud" | "quiet" | undefined;
    bite?: "nip" | "clamp" | undefined;
}

type RequiredKeepUndefinedDog = RequiredKeepUndefined<Dog>
/* type RequiredKeepUndefinedDog = {
    bark: "loud" | "quiet" | undefined;
    bite: "nip" | "clamp" | undefined;
} */

您可以將其視為以下轉換

  • {bark: "loud" | "quiet" | undefined, bite?: "nip" | "clamp" | undefined}
  • {bark: ["loud" | "quiet" | undefined], bite?: ["nip" | "clamp" | undefined] | undefined}
  • {bark: ["loud" | "quiet" | undefined], bite: ["nip" | "clamp" | undefined]}
  • {bark: "loud" | "quiet" | undefined, bite: "nip" | "clamp" | undefined}

好的,希望有幫助; 祝你好運!

代碼鏈接

我仍然喜歡更清潔的解決方案,但以下似乎有效:

我基本上創建了一個名為'undefined'的類型,我用這兩個替換/取消替換了真正的undefined類型:

type WrapUndefined<T> = {
    [P in keyof T]: undefined extends T[P] ? 'undefined' | T[P] : T[P];
};

type UnwrapUndefined<T> = {
    [P in keyof T]: 'undefined' extends T[P] ? Diff<T[P], 'undefined'> | undefined : T[P];
};

所以如果我有:

type Person = {
   firstName?: string;
}

然后WrapUndefined<Person>使它

firstName?: string | undefined | 'undefined';     // *

然后,您可以對此調用Required<T>以獲取此信息:

firstName: string | 'undefined';    // 'undefined' doesn't get removed now

然后用UnwrapUndefined<T>反轉它得到

firstName: string | undefined;

所以我然后創建一個單一類型來完成所有這些:

export type SmartRequired<T> = UnwrapUndefined<Required<WrapUndefined<T>>>;

如果我在我原來的Dog類型上運行這個問題,我會得到我想要的:

export type RequiredDog = SmartRequired <{

    bark: 'loud' | 'quiet' | undefined,
    bite?: 'nip' | 'clamp' | undefined
}>; 

這是哪個

type RequiredDog = {
    bark: "loud" | "quiet" | undefined;
    bite: "nip" | "clamp" | undefined;
}

* 高級說明:此步驟在 VSCode 中顯示為string | undefined string | undefined因為它似乎正在將 'undefined' 吸收到string 幸運的是,當您運行所有三個步驟時,它最終會得到正確的結果。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM