Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/EmptyTag/139.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Typescript 如何制作递归元组来描述逻辑运算符?_Typescript - Fatal编程技术网

Typescript 如何制作递归元组来描述逻辑运算符?

Typescript 如何制作递归元组来描述逻辑运算符?,typescript,Typescript,对于不同数量的参数,是否可以在不手动描述所有情况的情况下描述下一种类型 type Operator = '&&'|'||' type Logical<T> = ( | [Expression<T>, Operator, Expression<T> ] | [Expression<T>, Operator, Expression<T>, Operator, Expression<T> ] | [E

对于不同数量的参数,是否可以在不手动描述所有情况的情况下描述下一种类型

type Operator = '&&'|'||'
type Logical<T> = (
  | [Expression<T>, Operator, Expression<T> ] 
  | [Expression<T>, Operator, Expression<T>, Operator, Expression<T> ]
  | [Expression<T>, Operator, Expression<T>, Operator, Expression<T>, Operator, Expression<T> ]
  | ...
)
在以下情况下输入错误:

find([['id', '=', 10], ['type', '=', 'animal']])
find([['id', '=', 10], '&&', ['type', '=', 'human'], ['age', '>=', '40']])
find([['id', '=', 10], ['type', '=', 'human'], ['age', '>=', '40']])

这可能会起作用:

// The type of an array's elements
type ArrayType<T extends readonly unknown[]> = T extends readonly (infer U)[] ? U : never
// An array with at least 3 elements
type AtLeast3<T> = readonly [T, T, T, ...T[]]
// Enforces that T's last element is U
type EnforceLastEl<T, U> = T extends readonly [...unknown[], U] ? T : never

// Checks if T starts with A, and then recurses
type AltArr1<T extends readonly unknown[], A, B, InitialValue> =
  T extends [infer Head, ...infer Tail]
    ? Head extends A
      // Check if the rest starts with B
      ? AltArr2<Tail, A, B, InitialValue>
      // Invalid type
      : never
    // Empty array (we are done)
    : InitialValue

// Same as Alt1 except it checks if T starts with B
type AltArr2<T extends readonly unknown[], A, B, InitialValue> =
T extends [infer Head, ...infer Tail]
    ? Head extends B
      ? AltArr1<Tail, A, B, InitialValue>
      : never
    : InitialValue

// Enforces an array alternates between A and B and also ends with the first value (A)
type AltArr<T extends AtLeast3<unknown>, A, B> = EnforceLastEl<AltArr1<T, A, B, T>, A>

// Actual stuff specific to Logical

// Because you didn't provide the definition of Expression, I'm not sure if it
// will work with the actual definition
type Expression<T> = T

type LogicalInput<T> = Expression<T> | Operator
type LogicalInputType<T extends LogicalInput<unknown>> =
  T extends LogicalInput<infer U> ? U : never

type Logical<T extends AtLeast3<LogicalInput<unknown>>> =
  AltArr<T, Expression<LogicalInputType<ArrayType<T>>>, Operator>

declare const find: <T extends AtLeast3<LogicalInput<unknown>>>(
  ...args: Logical<T> extends never
    // If T isn't valid, Logical<T> will be never, so don't accept anything
    ? [never]
    // T is valid, accept the argument
    : [expr: T]
) => void

// Errors
find([1])
find([1, '&&'])
find([1, '&&', 2, '||'])
find(['&&', 1, '||'])

// This doesn't work, unfortunately
find([1, '&&', 2])

// Works
find([1, '&&', 2] as const)
find([1, '&&', 2, '||', 3] as const)
//数组元素的类型
类型ArrayType=T扩展为只读(推断U)[]?U:从来没有
//至少包含3个元素的数组
类型AtLeast3=只读[T,T,T,…T[]
//强制T的最后一个元素为U
类型EnforceLastEl=T扩展为只读[…未知[],U]?T:从来没有
//检查T是否以A开头,然后递归
AltArr1型=
T延伸[推断头部,…推断尾部]
? 头伸出一根绳子
//检查其余的是否以B开头
? 祭坛2
//无效类型
:从不
//空数组(我们完成了)
:初始值
//与Alt1相同,只是它检查T是否以B开头
AltArr2型=
T延伸[推断头部,…推断尾部]
? 头伸出B
? 祭坛1
:从不
:初始值
//强制数组在A和B之间交替,并以第一个值(A)结束
键入AltArr=EnforceLastEl

对于Typescript来说,严格键入这将是一件非常困难的事情。这可能是可能的,但毫无疑问,这将涉及一些疯狂的神秘泛型。非常感谢)我将继续使用您的示例进行实验
// The type of an array's elements
type ArrayType<T extends readonly unknown[]> = T extends readonly (infer U)[] ? U : never
// An array with at least 3 elements
type AtLeast3<T> = readonly [T, T, T, ...T[]]
// Enforces that T's last element is U
type EnforceLastEl<T, U> = T extends readonly [...unknown[], U] ? T : never

// Checks if T starts with A, and then recurses
type AltArr1<T extends readonly unknown[], A, B, InitialValue> =
  T extends [infer Head, ...infer Tail]
    ? Head extends A
      // Check if the rest starts with B
      ? AltArr2<Tail, A, B, InitialValue>
      // Invalid type
      : never
    // Empty array (we are done)
    : InitialValue

// Same as Alt1 except it checks if T starts with B
type AltArr2<T extends readonly unknown[], A, B, InitialValue> =
T extends [infer Head, ...infer Tail]
    ? Head extends B
      ? AltArr1<Tail, A, B, InitialValue>
      : never
    : InitialValue

// Enforces an array alternates between A and B and also ends with the first value (A)
type AltArr<T extends AtLeast3<unknown>, A, B> = EnforceLastEl<AltArr1<T, A, B, T>, A>

// Actual stuff specific to Logical

// Because you didn't provide the definition of Expression, I'm not sure if it
// will work with the actual definition
type Expression<T> = T

type LogicalInput<T> = Expression<T> | Operator
type LogicalInputType<T extends LogicalInput<unknown>> =
  T extends LogicalInput<infer U> ? U : never

type Logical<T extends AtLeast3<LogicalInput<unknown>>> =
  AltArr<T, Expression<LogicalInputType<ArrayType<T>>>, Operator>

declare const find: <T extends AtLeast3<LogicalInput<unknown>>>(
  ...args: Logical<T> extends never
    // If T isn't valid, Logical<T> will be never, so don't accept anything
    ? [never]
    // T is valid, accept the argument
    : [expr: T]
) => void

// Errors
find([1])
find([1, '&&'])
find([1, '&&', 2, '||'])
find(['&&', 1, '||'])

// This doesn't work, unfortunately
find([1, '&&', 2])

// Works
find([1, '&&', 2] as const)
find([1, '&&', 2, '||', 3] as const)