无序元组类型 [英] Unordered tuple type

查看:21
本文介绍了无序元组类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我只是在研究 Typescript 类型,我想知道如何定义一个类型,它是一个元组但具有无序元素类型.

我的意思是,拥有

type SimpleTuple = [number, string];const tup1: SimpleTuple = [7, `7`];//有效的const tup2: SimpleTuple = [`7`, 7];//'string' 不能赋值给 'number'//反之亦然

这在很多情况下都很有用,但是如果我不关心顺序或者我需要它是无序的怎么办.
上面的例子很简单,因为我可以定义

type SimpleUnorderedTuple = [数字,字符串] |[字符串,数字];const tup1: SimpleUnorderedTuple = [7, `7`];//有效的const tup2: SimpleUnorderedTuple = [`7`, 7];//有效的

但是,我可能有一堆类型......它们的组合逻辑会很痛苦

type ABunchOfTypes = 'these' |'是' |'一些' |'话' |'只是' |'为' |'的' |'例子';类型 ComplexUnorderedTuple =['these', 'are', 'some', 'words', 'just', 'for', 'the', 'example'] |['these', 'are', 'some', 'words', 'just', 'for', 'example', 'the'] |//等等 ...

这太疯狂了.有 !n 种可能的组合,其中 n 是元素的数量(我猜,我数学不太好!).

我正在努力实现类似的目标

type ABunchOfTypes = 'these' |'是' |'一些';输入 UnorderedTuple=;//...类型 ComplexUnorderedTuple = UnorderedTuple;

我在这篇文章

中找到<块引用>

我们添加到元组变量的任何后续值都可以是任何预定义的元组类型,没有特定的顺序.

但是我无法复制.如果我定义了一个包含两个元素的元组,如果 n 大于(或等于)元组长度,则不允许访问第 n 个位置.

解决方案

如果您正在寻找联合的排列类型,这将为您提供:

type ABunchOfTypes = 'these' |'是' |'一些' |'话' |'只是';type PushFront=((head: HeadT, ...tail: TailT) => void) extends ((...arr: infer ArrT) => void) ?ArrT:从不;类型CalculatePermutations= {[k 在 U]: ([排除<U,k>]扩展[从不]?PushFront<ResultT,k>:计算排列<排除,PushFront>)}[U];var 测试:CalculatePermutations= ['are', 'these', 'just', 'words', 'some'];

您可以尝试在此游乐场.

但是,这种方法存在局限性;我的实验表明 TypeScript 最多可以处理 7 个字符串的并集.有 8 个或更多字符串时,将显示错误.

更新

如果没有重复"是需要的,简单多了.

type ABunchOfTypes = 'these' |'是' |'一些' |'话' |'只是';type PushFront=((head: HeadT, ...tail: TailT) => void) extends ((...arr: infer ArrT) => void) ?ArrT:从不;type NoRepetition= {[k in U]:PushFront<ResultT,k>|NoRepetition<Exclude<U,k>,PushFront<ResultT,k>}[U];//好的var 测试:NoRepetition= ['are', 'these', 'just', 'words', 'some'];test = ['are', 'these', 'just'];测试 = ['是'];//不好test = ['are', 'these', 'are'];

请参阅此游乐场链接.

此外,使用即将推出的 TypeScript 4 语法,它仍然可以简化:

type ABunchOfTypes = 'these' |'是' |'一些' |'话' |'只是';//对于打字稿 4type NoRepetition= {[k in U]: [k, ...ResultT] |NoRepetition<Exclude<U,k>,[k,...ResultT]>}[U];//好的var 测试:NoRepetition= ['are', 'these', 'just', 'words', 'some'];test = ['are', 'these', 'just'];测试 = ['是'];//不好test = ['are', 'these', 'are'];

请参阅此 游乐场链接.

更新 2

以上两个假设你要求数组非空.如果你还想允许空数组,你可以这样做:

type ABunchOfTypes = 'these' |'是' |'一些' |'话' |'只是';//对于打字稿 4type NoRepetition= 结果T |{[k in U]:NoRepetition<Exclude<U,k>,[k,...ResultT]>}[U];//好的var 测试:NoRepetition= ['are', 'these', 'just', 'words', 'some'];test = ['are', 'these', 'just'];测试 = ['是'];测试 = [];//不好test = ['are', 'these', 'are'];

看到这个游乐场链接.

可以将 U extends string 替换为 U extends keyof any 以支持字符串、数字和符号的联合类型,但当前 TypeScript 的限制使其无法实现超越这一点.

I am just digging into Typescript typings and I wondered how to define a type which is a tuple but with unordered element types.

I mean, having

type SimpleTuple = [number, string];

const tup1: SimpleTuple = [7, `7`]; // Valid
const tup2: SimpleTuple = [`7`, 7]; // 'string' is not assignable to 'number'
                                    // and vice-versa

This is useful in many cases, but what if I don't care about order or I need it to be unordered.
The example above is quite trivial since I could define

type SimpleUnorderedTuple = [number, string] | [string, number];

const tup1: SimpleUnorderedTuple = [7, `7`]; // Valid
const tup2: SimpleUnorderedTuple = [`7`, 7]; // Valid

However, I may have a bunch of types... A combinatory logic uppon them would be painful

type ABunchOfTypes = 'these' | 'are' | 'some' | 'words' | 'just' | 'for' | 'the' | 'example';
type ComplexUnorderedTuple =
    ['these', 'are', 'some', 'words', 'just', 'for', 'the', 'example'] |
    ['these', 'are', 'some', 'words', 'just', 'for', 'example', 'the'] |
    // and so on ...

This is insane. There are !n possible combinations, where n is the number of elements (I guess, I am not too good at maths!).

I am trying to achieve something like

type ABunchOfTypes = 'these' | 'are' | 'some';
type UnorderedTuple<T> = ; //...

type ComplexUnorderedTuple = UnorderedTuple<ABunchOfTypes>;

I found in this article

Any subsequent value we add to the tuple variable can be any of the predefined tuple types in no particular order.

But I couldn't reproduce. If I define a tuple of two elements, I am not allowed to access to the nth position, if n is greater than (or equal) the tuple length.

解决方案

If you are looking for permutation type of a union, this will give you exactly that:

type ABunchOfTypes = 'these' | 'are' | 'some' | 'words' | 'just';

type PushFront<TailT extends any[], HeadT> =
    ((head: HeadT, ...tail: TailT) => void) extends ((...arr: infer ArrT) => void) ? ArrT : never;

type CalculatePermutations<U extends string, ResultT extends any[] = []> = {
    [k in U]: (
        [Exclude<U, k>] extends [never] ?
        PushFront<ResultT, k> :
        CalculatePermutations<Exclude<U, k>, PushFront<ResultT, k>>
    )
}[U];

var test: CalculatePermutations<ABunchOfTypes> = ['are', 'these', 'just', 'words', 'some'];

You can try it in this Playground.

There is a limitation to this approach, however; my experiment showed that TypeScript can at most process a union of 7 strings. With 8 or more strings, an error will shown.

Update

If "no repetition" is what is needed, it is a lot simpler.

type ABunchOfTypes = 'these' | 'are' | 'some' | 'words' | 'just';

type PushFront<TailT extends any[], HeadT> =
    ((head: HeadT, ...tail: TailT) => void) extends ((...arr: infer ArrT) => void) ? ArrT : never;

type NoRepetition<U extends string, ResultT extends any[] = []> = {
    [k in U]: PushFront<ResultT, k> | NoRepetition<Exclude<U, k>, PushFront<ResultT, k>>
}[U];

// OK
var test: NoRepetition<ABunchOfTypes> = ['are', 'these', 'just', 'words', 'some'];
test = ['are', 'these', 'just'];
test = ['are'];

// Not OK
test = ['are', 'these', 'are'];

See this Playground Link.

Also, with the upcoming TypeScript 4 syntax, it can be simplified still:

type ABunchOfTypes = 'these' | 'are' | 'some' | 'words' | 'just';

// for TypeScript 4 
type NoRepetition<U extends string, ResultT extends any[] = []> = {
    [k in U]: [k, ...ResultT] | NoRepetition<Exclude<U, k>, [k, ...ResultT]>
}[U];

// OK
var test: NoRepetition<ABunchOfTypes> = ['are', 'these', 'just', 'words', 'some'];
test = ['are', 'these', 'just'];
test = ['are'];

// Not OK
test = ['are', 'these', 'are'];

See this Playground Link.

Update 2

The above two assumes that you require the array to be non-empty. If you also want to allow empty array, you can do it like this:

type ABunchOfTypes = 'these' | 'are' | 'some' | 'words' | 'just';

// for TypeScript 4 
type NoRepetition<U extends string, ResultT extends any[] = []> = ResultT | {
    [k in U]: NoRepetition<Exclude<U, k>, [k, ...ResultT]>
}[U];

// OK
var test: NoRepetition<ABunchOfTypes> = ['are', 'these', 'just', 'words', 'some'];
test = ['are', 'these', 'just'];
test = ['are'];
test = [];

// Not OK
test = ['are', 'these', 'are'];

See this Playground Link.

It is possible to replace U extends string by U extends keyof any to support union types of strings, numbers and symbols, but the current limitation of TypeScript makes it impossible to go beyond this.

这篇关于无序元组类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆