首页 > 解决方案 > 从枚举推断元组类型?

问题描述

export enum DataType {
    UNKNOWN = 0x00,
    STRING = 0x01,
    FIXED_LENGTH_STRING = 0x02,
    FLOAT32 = 0x03,
    FLOAT64 = 0x04,
    DECIMAL = 0x05,
    NULLABLE_COMPACT_INT = 0x06,
}

export async function createTableWriteStream<T extends ReadonlyArray<any>>(path: string, options: FileOptions&TableWriteStreamOptions): Promise<TableWriteStream<T>> { ... }

const writeStream = await createTableWriteStream<[string,number|null|bigint]>(testFile, {
    flags: 'w',
    columns: [
        {
            name: "col1",
            type: DataType.STRING,
        },
        {
            name: "column 2",
            type: DataType.NULLABLE_COMPACT_INT,
        },
    ]
})

我想在DataType和 TS 类型之间创建一个映射,这样我就不需要TcreateTableWriteStream.

就像是:

interface TypeMap {
    [DataType.UNKNOWN]: never,
    [DataType.STRING]: string,
    [DataType.FIXED_LENGTH_STRING]: string,
    [DataType.FLOAT32]: number,
    [DataType.FLOAT64]: number,
    [DataType.DECIMAL]: number|string,
    [DataType.NULLABLE_COMPACT_INT]: number|bigint|null,
}

但是我不知道如何使用它来推断createTableWriteStreamfrom的返回类型options.columns.type。这可能吗?

打字稿游乐场

标签: typescript

解决方案


好的,这有点棘手。

首先,您需要准备从枚举到预期结果类型的映射。

type DataTypeMapping = {
  [DataType.UNKNOWN]: never,
  [DataType.STRING]: string,
  [DataType.FIXED_LENGTH_STRING]: string,
  [DataType.FLOAT32]: number,
  [DataType.FLOAT64]: number,
  [DataType.DECIMAL]: number|string,
  [DataType.NULLABLE_COMPACT_INT]: number|bigint|null,
}

接下来,您需要创建一些类型,将您的源列元组映射到目标结果元组。现在(从 typescript 4.2.3 开始)将元组映射到另一个元组有点棘手,尤其是当您尝试将某些特定(非抽象)元组映射到另一个元组时。这是因为元组本身是一个数组,除了元素之外还有一些属性(如长度、数组方法、迭代器等)。以下是有效的构造:

type Tuple<T> = [T, ...T[]];

type MapDataTypeImpl<T extends Tuple<ColumnSpec>> = {
  [K in keyof T]: T[K] extends ColumnSpec ? DataTypeMapping[T[K]['type']] : never
}
type MapDataType<T> = T extends Tuple<ColumnSpec> ? MapDataTypeImpl<T> : never;

(最初的想法是如何在 Typescript 3.0 中将元组“映射”到另一个元组类型

MapDataType您还可以在此处注意到使用和的两步实现MapDataTypeImpl。我不知道确切原因,但目前似乎不可能将其合并为一种类型。

最后一步是使您的列成为元组

interface TableWriteStreamOptions {
    columns: Tuple<ColumnSpec>
    ...
}

最后你可以像这样实现你的方法:

export async function createTableWriteStream<T extends TableWriteStreamOptions>(
  path: string, options: FileOptions & T): Promise<TableWriteStream<MapDataType<T['columns']>>> { 
    //  ...
    return new TableWriteStream()
}

并且根据您的要求,现在createTableWriteStream可以在没有显式类型参数的情况下使用。

这是一个工作示例


推荐阅读