TypeScript:某个值类型的对象属性元组的泛型类型



我想知道是否可以定义一个长度为2的元组[O,K]的泛型类型,称之为AccessorPair,其第一种类型O是对象,第二种类型K是该对象的键,这样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无法支持?关于这种类型,有没有我不知道的编程语言概念?欢迎任何讨论!

首先我们需要区分两个定义:typescript中的arraystuples

array视为一个长度未知的列表,类似于Rust中的vector

在编译期间,将tuple视为已知长度的列表。

为了处理[true, false]元组的允许密钥(其中只有两个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

游乐场

顺便说一句,由于您不知道元组中所有允许的对象,因此如果没有额外的函数,就不可能创建它。

最新更新