[英]Is it possible to remove a wider type from an literal union in Typescript?
[英]How can I remove a wider type from a union type without removing its subtypes in TypeScript?
使用 Exclude 運算符不起作用。
type test = Exclude<'a'|'b'|string, string>
// produces type test = never
我可以理解為什么“除了字符串”也意味着排除所有字符串文字,但是如何從'a'|'b'|string
獲取'a'|'b'
?
如果需要,請使用最新的 TypeScript。
用例如下:
假設第三方庫定義了這種類型:
export interface JSONSchema4 {
id?: string
$ref?: string
$schema?: string
title?: string
description?: string
default?: JSONSchema4Type
multipleOf?: number
maximum?: number
exclusiveMaximum?: boolean
minimum?: number
exclusiveMinimum?: boolean
maxLength?: number
minLength?: number
pattern?: string
// to allow third party extensions
[k: string]: any
}
現在,我想要做的是獲得 KNOWN 屬性的聯合:
type KnownProperties = Exclude<keyof JSONSchema4, string|number>
可以理解的是,這會失敗並給出一個空類型。
如果您正在閱讀這篇文章,但我被一輛公共汽車撞到了,那么這個問題的答案可能會在這個 GitHub 線程 中找到。
我在這個 GitHub 線程中從@ferdaber那里得到了一個解決方案。
編輯:事實證明,它是由@ajafff 於 1986 年出版的
該解決方案需要 TypeScript 2.8 的條件類型,如下所示:
type KnownKeys<T> = {
[K in keyof T]: string extends K ? never : number extends K ? never : K
} extends { [_ in keyof T]: infer U } ? U : never;
以下是我的解釋嘗試:
該解決方案基於string
擴展string
(就像'a'
extends string
)但string
不擴展'a'
的事實,對於數字也是如此。 基本上,我們必須將extends
視為“進入”
首先它創建一個映射類型,其中對於 T 的每個鍵,值是:
然后,它本質上是 valueof 來獲得所有值的聯合:
type ValuesOf<T> = T extends { [_ in keyof T]: infer U } ? U : never
或者,更准確地說:
interface test {
req: string
opt?: string
[k: string]: any
}
type FirstHalf<T> = {
[K in keyof T]: string extends K ? never : number extends K ? never : K
}
type ValuesOf<T> = T extends { [_ in keyof T]: infer U } ? U : never
// or equivalently, since T here, and T in FirstHalf have the same keys,
// we can use T from FirstHalf instead:
type SecondHalf<First, T> = First extends { [_ in keyof T]: infer U } ? U : never;
type a = FirstHalf<test>
//Output:
type a = {
[x: string]: never;
req: "req";
opt?: "opt" | undefined;
}
type a2 = ValuesOf<a> // "req" | "opt" // Success!
type a2b = SecondHalf<a, test> // "req" | "opt" // Success!
// Substituting, to create a single type definition, we get @ferdaber's solution:
type KnownKeys<T> = {
[K in keyof T]: string extends K ? never : number extends K ? never : K
} extends { [_ in keyof T]: infer U } ? U : never;
// type b = KnownKeys<test> // "req" | "opt" // Absolutely glorious!
GitHub 線程中的說明,以防有人在那里提出異議
每個接受的答案: https : //stackoverflow.com/a/51955852/714179 。 在 TS 4.3.2 這有效:
export type KnownKeys<T> = keyof {
[K in keyof T as string extends K ? never : number extends K ? never : K]: never
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.