【问题标题】:Infer tuple type from enum?从枚举推断元组类型?
【发布时间】:2021-08-05 03:31:09
【问题描述】:
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 类型之间创建一个映射,这样我就不需要为createTableWriteStream 指定T。

类似:

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,
}

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

TypeScript Playground

【问题讨论】:

  • 请考虑修改此问题中的代码以构成minimal reproducible example,当将其放入像The TypeScript Playground (link to code) 这样的独立IDE 时,清楚地表明您面临的问题没有未声明的类型或值.这将使那些想要帮助您的人立即着手解决问题,而无需首先重新创建它。它将使您得到的任何答案都可以针对定义明确的用例进行测试。

标签: typescript


【解决方案1】:

好的,这有点棘手。

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

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;

(最初的想法归功于How to 'map' a Tuple to another Tuple type in 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 可以在没有显式类型参数的情况下使用。

这是working example。

【讨论】:

    猜你喜欢
    • 2018-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-14
    • 1970-01-01
    • 2020-08-29
    • 1970-01-01
    相关资源
    最近更新 更多