簡體   English   中英

TypeScript:某個值類型的對象屬性元組的通用類型

[英]TypeScript: Generic type of object-property tuple of certain value type

我想知道是否可以定義一個長度為2的元組[O,K]的泛型類型,稱之為AccessorPair,它的第一個類型O是object,第二個類型K是那個object的關鍵,這樣O [K] 擴展了某個類型 T。

例如,

const foo: AccessorPair<number> = [new Array(), 'length']
const bar: AccessorPair<boolean> = [[true, false], 0]

我的第一次嘗試是

type AccessorPair<T> = T extends (infer O)[infer K] ? [O, K] : never

但它只會導致“類型'K'不能用於索引類型'O'.ts(2536)”

我試圖解決

type ValueOf<O, P extends keyof O> = O[P]
type AccessorPair<T> = T extends ValueOf<infer O, infer P> ? [O, P] : never

它總是解析為“從不”。

TypeScript 是否支持這樣的定義太模糊? 關於這種類型,有沒有我不知道的編程語言概念? 任何討論表示贊賞!

首先我們需要區分兩個定義: arrays和typescript中的tuples

array視為未知長度的列表,類似於 Rust 中的vector

tuple視為在編譯期間已知長度的列表。

為了處理[true, false]元組的允許鍵,其中只有兩個0 | 1 0 | 1我們需要編寫一個小的實用程序類型:

type IsTuple<T> =
    (T extends Array<any> ?
        (T['length'] extends number
            ? (number extends T['length']
                ? false
                : true)
            : true)
        : false)

{
    type _ = IsTuple<[1, 2]> // true
    type __ = IsTuple<number[]> // false
    type ___ = IsTuple<{ length: 2 }> // false
}

type AllowedTupleLength<
    T extends ReadonlyArray<unknown>,
    Length extends number = never
    > = T extends readonly [infer _, ...infer Tail]
    ? AllowedTupleLength<Tail, Length | Tail['length']>
    : T extends readonly []
    ? Length
    : never;

type Result = AllowedTupleLength<[0,0]> // 1 | 0

現在我們需要一個實用程序,它可以有條件地返回元組和數組的允許鍵:

type ComputeKeys<Tuple extends any[]> =
    IsTuple<Tuple[0]> extends true ? AllowedTupleLength<Tuple[0]> : keyof Tuple[0]

ComputeKeys[true, false]返回1|0 ,為常規數組返回所有數組鍵。

順便說一句,您是否允許使用forEach, reduce, map鍵作為元組中的第二個元素?

此外,我們需要處理所有非數組對象。 讓我們在一個聯合中創建具有所有可序列化類型的Json類型:

type Json = | string | number | boolean | { [prop: string]: Json } | Array<Json>

type IsTuple<T> =
    (T extends Array<any> ?
        (T['length'] extends number
            ? (number extends T['length']
                ? false
                : true)
            : true)
        : false)

type AllowedTupleLength<
    T extends ReadonlyArray<unknown>,
    Length extends number = never
    > = T extends readonly [infer _, ...infer Tail]
    ? AllowedTupleLength<Tail, Length | Tail['length']>
    : T extends readonly []
    ? Length
    : never;

type ComputeKeys<Tuple extends any[]> =
    IsTuple<Tuple[0]> extends true ? AllowedTupleLength<Tuple[0]> : keyof Tuple[0]


function handleTuple<
    Elem extends Exclude<Json, any[]>, // overload signature for non array serializable values
    Tuple extends Elem[]
>(tuple: [...Tuple, keyof Tuple[0]]): [...Tuple]
function handleTuple<
    Elem,
    NestedTuple extends Elem[],
    Tuple extends [...NestedTuple][]
>(tuple: [...Tuple, ComputeKeys<Tuple>]): [...Tuple]
function handleTuple(tuple: unknown[]) {
    return tuple
}

handleTuple([[true, false], 1]) // ok
handleTuple([[true, false], 2]) // expected error, index is too big

handleTuple([new Array(), 'length']) // ok
handleTuple([new Array(), 2]) // allowed because we don't know exact length of array
handleTuple([{ name: 'John', age: 32 }, 'name']) // allowed because we don't know exact length of array

操場

順便說一句,由於您不知道元組中所有允許的對象,因此如果沒有額外的 function,就不可能做到這一點。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM