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)