代码之家  ›  专栏  ›  技术社区  ›  mpen

从枚举推断元组类型?

  •  0
  • mpen  · 技术社区  · 3 年前
    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类型,这样我就不需要指定 T 对于 createTableWriteStream .

    类似于:

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

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

    TypeScript Playground

    0 回复  |  直到 3 年前
        1
  •  2
  •   Artyom Kozhemiakin    3 年前

    好吧,这有点棘手。

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

    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 .