我想将对象类型的键映射到对象,其中:

  • 每个密钥都是原始类型中的一个密钥
  • 如果值的类型是联合类型,则每个值都是{enum:数组
  • 如果值的类型是not联合类型,则每个值都是{enum:Never

Example

type OriginalType = {
    foo: "a" | "b";
    bar: "c";
    foobar: Record<string, string>;
};

type MappedType<T> = { ... };

type ResultType = MappedType<OriginalType>;

// ResultType = {
//    foo: { enum: ["a", "b"] }, // or foo: { enum: Array<"a" | "b"> }
//    bar: { enum: never },
//    foobar: { enum: never },
//}

我知道如何将键和值映射到新类型,但不知道如何确定类型是否为联合类型:

type IsUnion<T> = ...

type MappedType<T> = {
    [K in keyof T]: IsUnion<T[K]> extends true ? { enum: Array<T[K]> } : never;
};

推荐答案

TypeScrip directly不支持区分联合和非联合,因此任何用户定义的实现都可能有奇怪的边缘情况.检测联合类型的一种可能方法是使用distributive conditional type将类型拆分为其联合成员,并将每个成员与整个未拆分类型进行比较.如果类型是联合,则每一件都不同于整体.否则将只有一块,它将与整体相同.(或者,如果输入是never,就会有零块,但希望这是一种边缘情况,我不必担心.)

type IsUnion<T, U = T> = 
  T extends unknown ? [U] extends [T] ? false : true : never;

这里,我使用default generic type argumentT复制到另一个类型参数U中.我们将T拆分成联合成员(通过分配条件类型T extends unknown ? ⋯ : never,而我们保持U不拆分)(通过non-分配条件类型[U] extends [T] ? false : true.让我们来测试一下:

type U = IsUnion<number>; // false
type V = IsUnion<string | number>; // true

看起来很合理.对于您的示例:

type MappedType<T> = {
  [K in keyof T]: IsUnion<T[K]> extends true ? { enum: Array<T[K]> } : never;
};
type OriginalType = {
  foo: "a" | "b";
  bar: "c";
  foobar: Record<string, string>;
};
type ResultType = MappedType<OriginalType>;
/* type ResultType = {
    foo: {
        enum: ("a" | "b")[];
    };
    bar: never;
    foobar: never;
} */

看上go 不错.

Playground link to code

Typescript相关问答推荐

具有映射返回类型的通用设置实用程序

用泛型类型覆盖父类函数导致类型y中的Property x不能赋给基类型Parent中的相同属性."'''''' "

如何为父类构造函数中的修饰属性赋值?

如何在单击停止录制按钮后停用摄像机?(使用React.js和Reaction-Media-Recorder)

类型脚本`Return;`vs`Return unfined;`

编剧错误:正在等待Expect(Locator).toBeVisible()

打印脚本中的动态函数重载

在VSCode中显示eslint错误,但在终端中运行eslint命令时不显示?(Vite,React,TypeScript)

打字错误推断

在抽象类属性定义中扩展泛型类型

使用Type脚本更新对象属性

映射类型不是数组类型

T的typeof键的Typescript定义

TypeScript:方法获胜';t接受较窄类型作为参数

可以';t使用t正确地索引对象;联合;索引类型

如何在TypeScript中声明逆变函数成员?

带动态键的 TS 功能

解析错误:DeprecationError: 'originalKeywordKind' 自 v5.0.0 起已被弃用,无法再使用

为什么 typescript 在对象合并期间无法判断无效键?

将函数签名合并到重载中