gpt4 book ai didi

typescript - 如何在不删除 TypeScript 中的子类型的情况下从联合类型中删除更广泛的类型?

转载 作者:搜寻专家 更新时间:2023-10-30 20:41:47 26 4
gpt4 key购买 nike

使用排除运算符不起作用。

type test = Exclude<'a'|'b'|string, string>
// produces type test = never

我能理解为什么“除了字符串”也意味着排除所有字符串文字,但我如何从 'a'|'b' 中获取 '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
}

现在,我想做的是获得已知属性的联合:

type KnownProperties = Exclude<keyof JSONSchema4, string|number>

有点可以理解,这会失败并给出一个空类型。

如果您正在阅读本文但我被公共(public)汽车撞了,那么可以在 this GitHub thread 中找到答案.

最佳答案

当前解决方案 (Typescript 4.1 +)

2021 年编辑: 2.8实现KnownKeys<T>broken since Typescript 4.3.1-rc ,而是使用 key remapping 的新的、更具语义的实现4.1 起可用:

type RemoveIndex<T> = {
[ K in keyof T as string extends K ? never : number extends K ? never : K ] : T[K]
};

然后可以按如下方式使用:

type KnownKeys<T> = keyof RemoveIndex<T>;

interface test {
req: string
opt?: string
[k: string]: any
}

type demo = KnownKeys<test>; // "req" | "opt" // Absolutely glorious!

以下是预4.1的保留解决方案 typescript 版本:


我从 @ferdaber 得到了解决方案在 this GitHub thread .

编辑:结果是,小张旗鼓,published in 1986通过 @ajafff

该解决方案需要 TypeScript 2.8 的 Conditional Types并进行如下:

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' 扩展了 string )但是 string不扩展 'a' ,对于数字也是如此。基本上,我们必须想到extends作为“进入”

首先它创建一个映射类型,其中对于 T 的每个键,值是:

  • if string extends key (key is string, not a subtype) => 从不
  • if number extends key (key is number, not a subtype) => never
  • 否则,实际的字符串键

然后,它基本上执行 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!

Explaination in GitHub thread万一那边有人反对

关于typescript - 如何在不删除 TypeScript 中的子类型的情况下从联合类型中删除更广泛的类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51954558/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com